mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-29 08:33:07 +00:00
modify expectancy and expectancy ratio
This commit is contained in:
@@ -203,21 +203,48 @@ def calculate_expectancy(trades: pd.DataFrame) -> float:
|
|||||||
if len(trades) == 0:
|
if len(trades) == 0:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
expectancy = 1
|
expectancy = 0
|
||||||
|
|
||||||
profit_sum = trades.loc[trades['profit_abs'] > 0, 'profit_abs'].sum()
|
winning_trades = trades.loc[trades['profit_abs'] > 0]
|
||||||
loss_sum = abs(trades.loc[trades['profit_abs'] < 0, 'profit_abs'].sum())
|
losing_trades = trades.loc[trades['profit_abs'] < 0]
|
||||||
nb_win_trades = len(trades.loc[trades['profit_abs'] > 0])
|
profit_sum = winning_trades['profit_abs'].sum()
|
||||||
nb_loss_trades = len(trades.loc[trades['profit_abs'] < 0])
|
loss_sum = abs(losing_trades['profit_abs'].sum())
|
||||||
|
nb_win_trades = len(winning_trades)
|
||||||
|
nb_loss_trades = len(losing_trades)
|
||||||
|
|
||||||
if (nb_win_trades > 0) and (nb_loss_trades > 0):
|
average_win = profit_sum / nb_win_trades
|
||||||
average_win = profit_sum / nb_win_trades
|
average_loss = loss_sum / nb_loss_trades
|
||||||
average_loss = loss_sum / nb_loss_trades
|
winrate = nb_win_trades / len(trades)
|
||||||
risk_reward_ratio = average_win / average_loss
|
loserate = nb_loss_trades / len(trades)
|
||||||
winrate = nb_win_trades / len(trades)
|
expectancy = (winrate * average_win) - (loserate * average_loss)
|
||||||
expectancy = ((1 + risk_reward_ratio) * winrate) - 1
|
|
||||||
elif nb_win_trades == 0:
|
return expectancy
|
||||||
expectancy = 0
|
|
||||||
|
|
||||||
|
def calculate_expectancy_ratio(trades: pd.DataFrame) -> float:
|
||||||
|
"""
|
||||||
|
Calculate expectancy ratio
|
||||||
|
:param trades: DataFrame containing trades (requires columns close_date and profit_abs)
|
||||||
|
:return: expectancy ratio
|
||||||
|
"""
|
||||||
|
|
||||||
|
expectancy_ratio = float('inf')
|
||||||
|
|
||||||
|
if len(trades) > 0:
|
||||||
|
winning_trades = trades.loc[trades['profit_abs'] > 0]
|
||||||
|
losing_trades = trades.loc[trades['profit_abs'] < 0]
|
||||||
|
profit_sum = winning_trades['profit_abs'].sum()
|
||||||
|
loss_sum = abs(losing_trades['profit_abs'].sum())
|
||||||
|
nb_win_trades = len(winning_trades)
|
||||||
|
nb_loss_trades = len(losing_trades)
|
||||||
|
|
||||||
|
average_win = (profit_sum / nb_win_trades) if nb_win_trades > 0 else 0
|
||||||
|
average_loss = (loss_sum / nb_loss_trades) if nb_loss_trades > 0 else 0
|
||||||
|
|
||||||
|
if (average_loss > 0):
|
||||||
|
risk_reward_ratio = average_win / average_loss
|
||||||
|
winrate = nb_win_trades / len(trades)
|
||||||
|
expectancy = ((1 + risk_reward_ratio) * winrate) - 1
|
||||||
|
|
||||||
return expectancy
|
return expectancy
|
||||||
|
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
('Calmar', f"{strat_results['calmar']:.2f}" if 'calmar' in strat_results else 'N/A'),
|
('Calmar', f"{strat_results['calmar']:.2f}" if 'calmar' in strat_results else 'N/A'),
|
||||||
('Profit factor', f'{strat_results["profit_factor"]:.2f}' if 'profit_factor'
|
('Profit factor', f'{strat_results["profit_factor"]:.2f}' if 'profit_factor'
|
||||||
in strat_results else 'N/A'),
|
in strat_results else 'N/A'),
|
||||||
('Expectancy', f"{strat_results['expectancy']:.2f}" if 'expectancy'
|
('Expectancy Ratio', f"{strat_results['expectancy_ratio']:.2f}" if 'expectancy_ratio'
|
||||||
in strat_results else 'N/A'),
|
in strat_results else 'N/A'),
|
||||||
('Trades per day', strat_results['trades_per_day']),
|
('Trades per day', strat_results['trades_per_day']),
|
||||||
('Avg. daily profit %',
|
('Avg. daily profit %',
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ from pandas import DataFrame, concat, to_datetime
|
|||||||
|
|
||||||
from freqtrade.constants import BACKTEST_BREAKDOWNS, DATETIME_PRINT_FORMAT, IntOrInf
|
from freqtrade.constants import BACKTEST_BREAKDOWNS, DATETIME_PRINT_FORMAT, IntOrInf
|
||||||
from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum,
|
from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum,
|
||||||
calculate_expectancy, calculate_market_change,
|
calculate_expectancy, calculate_expectancy_ratio,
|
||||||
calculate_max_drawdown, calculate_sharpe, calculate_sortino)
|
calculate_market_change, calculate_max_drawdown,
|
||||||
|
calculate_sharpe, calculate_sortino)
|
||||||
from freqtrade.misc import decimals_per_coin, round_coin_value
|
from freqtrade.misc import decimals_per_coin, round_coin_value
|
||||||
|
|
||||||
|
|
||||||
@@ -414,7 +415,7 @@ def generate_strategy_stats(pairlist: List[str],
|
|||||||
'profit_total_long_abs': results.loc[~results['is_short'], 'profit_abs'].sum(),
|
'profit_total_long_abs': results.loc[~results['is_short'], 'profit_abs'].sum(),
|
||||||
'profit_total_short_abs': results.loc[results['is_short'], 'profit_abs'].sum(),
|
'profit_total_short_abs': results.loc[results['is_short'], 'profit_abs'].sum(),
|
||||||
'cagr': calculate_cagr(backtest_days, start_balance, content['final_balance']),
|
'cagr': calculate_cagr(backtest_days, start_balance, content['final_balance']),
|
||||||
'expectancy': calculate_expectancy(results),
|
'expectancy_ratio': calculate_expectancy_ratio(results),
|
||||||
'sortino': calculate_sortino(results, min_date, max_date, start_balance),
|
'sortino': calculate_sortino(results, min_date, max_date, start_balance),
|
||||||
'sharpe': calculate_sharpe(results, min_date, max_date, start_balance),
|
'sharpe': calculate_sharpe(results, min_date, max_date, start_balance),
|
||||||
'calmar': calculate_calmar(results, min_date, max_date, start_balance),
|
'calmar': calculate_calmar(results, min_date, max_date, start_balance),
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ from freqtrade import __version__
|
|||||||
from freqtrade.configuration.timerange import TimeRange
|
from freqtrade.configuration.timerange import TimeRange
|
||||||
from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT, Config
|
from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT, Config
|
||||||
from freqtrade.data.history import load_data
|
from freqtrade.data.history import load_data
|
||||||
from freqtrade.data.metrics import calculate_max_drawdown
|
from freqtrade.data.metrics import (calculate_expectancy, calculate_expectancy_ratio,
|
||||||
|
calculate_max_drawdown)
|
||||||
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, MarketDirection, SignalDirection,
|
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, MarketDirection, SignalDirection,
|
||||||
State, TradingMode)
|
State, TradingMode)
|
||||||
from freqtrade.exceptions import ExchangeError, PricingError
|
from freqtrade.exceptions import ExchangeError, PricingError
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, analyze_trade_parallelis
|
|||||||
load_backtest_metadata, load_trades, load_trades_from_db)
|
load_backtest_metadata, load_trades, load_trades_from_db)
|
||||||
from freqtrade.data.history import load_data, load_pair_history
|
from freqtrade.data.history import load_data, load_pair_history
|
||||||
from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum,
|
from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum,
|
||||||
calculate_expectancy, calculate_market_change,
|
calculate_expectancy, calculate_expectancy_ratio,
|
||||||
calculate_max_drawdown, calculate_sharpe, calculate_sortino,
|
calculate_market_change, calculate_max_drawdown,
|
||||||
calculate_underwater, combine_dataframes_with_mean,
|
calculate_sharpe, calculate_sortino, calculate_underwater,
|
||||||
create_cum_profit)
|
combine_dataframes_with_mean, create_cum_profit)
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.util import dt_utc
|
from freqtrade.util import dt_utc
|
||||||
from tests.conftest import CURRENT_TEST_STRATEGY, create_mock_trades
|
from tests.conftest import CURRENT_TEST_STRATEGY, create_mock_trades
|
||||||
@@ -339,16 +339,16 @@ def test_calculate_csum(testdatadir):
|
|||||||
csum_min, csum_max = calculate_csum(DataFrame())
|
csum_min, csum_max = calculate_csum(DataFrame())
|
||||||
|
|
||||||
|
|
||||||
def test_calculate_expectancy(testdatadir):
|
def test_calculate_expectancy_ratio(testdatadir):
|
||||||
filename = testdatadir / "backtest_results/backtest-result.json"
|
filename = testdatadir / "backtest_results/backtest-result.json"
|
||||||
bt_data = load_backtest_data(filename)
|
bt_data = load_backtest_data(filename)
|
||||||
|
|
||||||
expectancy = calculate_expectancy(DataFrame())
|
expectancy_ratio = calculate_expectancy_ratio(DataFrame())
|
||||||
assert expectancy == 0.0
|
assert expectancy_ratio == 0.0
|
||||||
|
|
||||||
expectancy = calculate_expectancy(bt_data)
|
expectancy_ratio = calculate_expectancy_ratio(bt_data)
|
||||||
assert isinstance(expectancy, float)
|
assert isinstance(expectancy_ratio, float)
|
||||||
assert pytest.approx(expectancy) == 0.07151374226574791
|
assert pytest.approx(expectancy_ratio) == 0.07151374226574791
|
||||||
|
|
||||||
|
|
||||||
def test_calculate_sortino(testdatadir):
|
def test_calculate_sortino(testdatadir):
|
||||||
|
|||||||
Reference in New Issue
Block a user