Add example calculation

This commit is contained in:
Matthias 2022-07-31 10:32:16 +02:00
parent 2cacb3767f
commit 04d4f15dff
3 changed files with 43 additions and 10 deletions

View File

@ -629,7 +629,7 @@ class AwesomeStrategy(IStrategy):
The `position_adjustment_enable` strategy property enables the usage of `adjust_trade_position()` callback in the strategy.
For performance reasons, it's disabled by default and freqtrade will show a warning message on startup if enabled.
`adjust_trade_position()` can be used to perform additional orders, for example to manage risk with DCA (Dollar Cost Averaging) or to increase or decrease winning positions.
`adjust_trade_position()` can be used to perform additional orders, for example to manage risk with DCA (Dollar Cost Averaging) or to increase or decrease positions.
`max_entry_position_adjustment` property is used to limit the number of additional buys per trade (on top of the first buy) that the bot can execute. By default, the value is -1 which means the bot have no limit on number of adjustment buys.
@ -652,12 +652,12 @@ Position adjustments will always be applied in the direction of the trade, so a
!!! Warning
Stoploss is still calculated from the initial opening price, not averaged price.
Regular stoploss rules still apply (cannot move down).
!!! Warning "/stopbuy"
While `/stopbuy` command stops the bot from entering new trades, the position adjustment feature will continue buying new orders on existing trades.
!!! Warning "Backtesting"
During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so performance will be affected.
During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so run-time performance will be affected.
``` python
from freqtrade.persistence import Trade
@ -678,7 +678,7 @@ class DigDeeperStrategy(IStrategy):
max_dca_multiplier = 5.5
# This is called when placing the initial order (opening trade)
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: Optional[float], max_stake: float,
leverage: float, entry_tag: Optional[str], side: str,
**kwargs) -> float:
@ -757,6 +757,25 @@ def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: f
```
### Position adjust calculations
* Entry rates are calculated using weighted averages.
* Exits will not influence the average entry rate.
* Partial exit relative profit is relative to the average entry price at this point.
* Final exit relative profit is calculated based on the total invested capital. (See example below)
??? example "Calculation example"
*This example assumes 0 fees for simplicity, and a long position on an imaginary coin.*
* Buy 100@8\$
* Buy 100@9\$ -> Avg price: 8.5\$
* Sell 100@10\$ -> Avg price: 8.5\$, realized profit 150\$, 17.65%
* Buy 150@11\$ -> Avg price: 10\$, realized profit 150\$, 17.65%
* Sell 100@12\$ -> Avg price: 10\$, total realized profit 350\$, 20%
* Sell 150@14\$ -> Avg price: 10\$, total realized profit 950\$, 40%
The total profit for this trade was 950$ on a 3350$ investment (`100@8$ + 100@9$ + 150@11$`). As such - the final relative profit is 28.35% (`950 / 3350`).
## Adjust Entry Price
The `adjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles.

View File

@ -485,6 +485,7 @@ class Telegram(RPCHandler):
sumA += amount * filled_orders[y]["safe_price"]
sumB += amount
prev_avg_price = sumA / sumB
# TODO: This calculation ignores fees.
price_to_1st_entry = ((cur_entry_average - first_avg) / first_avg)
minus_on_entry = 0
if prev_avg_price:

View File

@ -2835,7 +2835,7 @@ def test_order_to_ccxt(limit_buy_order_open):
(('buy', 100, 15), (200.0, 12.5, 2500.0, 0.0, None, None)),
(('sell', 50, 12), (150.0, 12.5, 1875.0, -25.0, -25.0, -0.04)),
(('sell', 100, 20), (50.0, 12.5, 625.0, 725.0, 750.0, 0.60)),
(('sell', 50, 5), (50.0, 12.5, 625.0, 725.0, -375.0, -0.60)),
(('sell', 50, 5), (50.0, 12.5, 625.0, 350.0, -375.0, -0.60)),
],
'end_profit': 350.0,
'end_profit_ratio': 0.14,
@ -2847,7 +2847,7 @@ def test_order_to_ccxt(limit_buy_order_open):
(('buy', 100, 15), (200.0, 12.5, 2500.0, 0.0, None, None)),
(('sell', 50, 12), (150.0, 12.5, 1875.0, -28.0625, -28.0625, -0.044788)),
(('sell', 100, 20), (50.0, 12.5, 625.0, 713.8125, 741.875, 0.59201995)),
(('sell', 50, 5), (50.0, 12.5, 625.0, 713.8125, -377.1875, -0.60199501)),
(('sell', 50, 5), (50.0, 12.5, 625.0, 336.625, -377.1875, -0.60199501)),
],
'end_profit': 336.625,
'end_profit_ratio': 0.1343142,
@ -2860,7 +2860,7 @@ def test_order_to_ccxt(limit_buy_order_open):
(('sell', 100, 11), (100.0, 5.0, 500.0, 596.0, 596.0, 1.189027)),
(('buy', 150, 15), (250.0, 11.0, 2750.0, 596.0, 596.0, 1.189027)),
(('sell', 100, 19), (150.0, 11.0, 1650.0, 1388.5, 792.5, 0.7186579)),
(('sell', 150, 23), (150.0, 11.0, 1650.0, 1388.5, 1787.25, 1.08048062)),
(('sell', 150, 23), (150.0, 11.0, 1650.0, 3175.75, 1787.25, 1.08048062)),
],
'end_profit': 3175.75,
'end_profit_ratio': 0.9747170,
@ -2874,11 +2874,24 @@ def test_order_to_ccxt(limit_buy_order_open):
(('sell', 100, 11), (100.0, 5.0, 500.0, 600.0, 600.0, 1.2)),
(('buy', 150, 15), (250.0, 11.0, 2750.0, 600.0, 600.0, 1.2)),
(('sell', 100, 19), (150.0, 11.0, 1650.0, 1400.0, 800.0, 0.72727273)),
(('sell', 150, 23), (150.0, 11.0, 1650.0, 1400.0, 1800.0, 1.09090909)),
(('sell', 150, 23), (150.0, 11.0, 1650.0, 3200.0, 1800.0, 1.09090909)),
],
'end_profit': 3200.0,
'fee': 0.0,
'end_profit_ratio': 0.98461538,
'fee': 0.0,
},
{
'orders': [
(('buy', 100, 8), (100.0, 8.0, 800.0, 0.0, None, None)),
(('buy', 100, 9), (200.0, 8.5, 1700.0, 0.0, None, None)),
(('sell', 100, 10), (100.0, 8.5, 850.0, 150.0, 150.0, 0.17647059)),
(('buy', 150, 11), (250.0, 10, 2500.0, 150.0, 150.0, 0.17647059)),
(('sell', 100, 12), (150.0, 10.0, 1500.0, 350.0, 350.0, 0.2)),
(('sell', 150, 14), (150.0, 10.0, 1500.0, 950.0, 950.0, 0.40)),
],
'end_profit': 950.0,
'end_profit_ratio': 0.283582,
'fee': 0.0,
},
])
def test_recalc_trade_from_orders_dca(data) -> None:
@ -2940,7 +2953,7 @@ def test_recalc_trade_from_orders_dca(data) -> None:
assert trade.open_rate == result[1]
assert trade.stake_amount == result[2]
# TODO: enable the below.
# assert pytest.approx(trade.realized_profit) == result[3]
assert pytest.approx(trade.realized_profit) == result[3]
# assert pytest.approx(trade.close_profit_abs) == result[4]
assert pytest.approx(trade.close_profit) == result[5]