fix: properly value open positions using last kline price for max_drawdown calculation
- Track last_kline_price during kline processing - Use last_kline_price instead of entry price for open position valuation - Add final marked-to-market value to portfolio_values for max_drawdown calculation - This fixes the issue where max_drawdown exceeded stop_loss percentage
This commit is contained in:
@@ -18,14 +18,11 @@ class BacktestEngine:
|
|||||||
)
|
)
|
||||||
self.bot_id = config.get("bot_id")
|
self.bot_id = config.get("bot_id")
|
||||||
self.strategy_config = config.get("strategy_config", {})
|
self.strategy_config = config.get("strategy_config", {})
|
||||||
print(f"[DEBUG] strategy_config received: {self.strategy_config}")
|
|
||||||
self.conditions = self.strategy_config.get("conditions", [])
|
self.conditions = self.strategy_config.get("conditions", [])
|
||||||
self.actions = self.strategy_config.get("actions", [])
|
self.actions = self.strategy_config.get("actions", [])
|
||||||
self.risk_management = self.strategy_config.get("risk_management", {})
|
self.risk_management = self.strategy_config.get("risk_management", {})
|
||||||
print(f"[DEBUG] risk_management: {self.risk_management}")
|
|
||||||
self.stop_loss_percent = self.risk_management.get("stop_loss_percent")
|
self.stop_loss_percent = self.risk_management.get("stop_loss_percent")
|
||||||
self.take_profit_percent = self.risk_management.get("take_profit_percent")
|
self.take_profit_percent = self.risk_management.get("take_profit_percent")
|
||||||
print(f"[DEBUG] stop_loss_percent: {self.stop_loss_percent}, take_profit_percent: {self.take_profit_percent}")
|
|
||||||
self.initial_balance = config.get("initial_balance", 10000.0)
|
self.initial_balance = config.get("initial_balance", 10000.0)
|
||||||
self.current_balance = self.initial_balance
|
self.current_balance = self.initial_balance
|
||||||
self.position = 0.0
|
self.position = 0.0
|
||||||
@@ -36,6 +33,7 @@ class BacktestEngine:
|
|||||||
self.running = False
|
self.running = False
|
||||||
self.progress = 0
|
self.progress = 0
|
||||||
self.total_klines = 0
|
self.total_klines = 0
|
||||||
|
self.last_kline_price: Optional[float] = None # Track last price for open position valuation
|
||||||
|
|
||||||
async def run(self) -> Dict[str, Any]:
|
async def run(self) -> Dict[str, Any]:
|
||||||
self.running = True
|
self.running = True
|
||||||
@@ -121,6 +119,8 @@ class BacktestEngine:
|
|||||||
price = float(kline.get("close", 0))
|
price = float(kline.get("close", 0))
|
||||||
if price <= 0:
|
if price <= 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
self.last_kline_price = price # Track last price for open position valuation
|
||||||
|
|
||||||
timestamp = kline.get("timestamp", 0)
|
timestamp = kline.get("timestamp", 0)
|
||||||
|
|
||||||
@@ -316,10 +316,16 @@ class BacktestEngine:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _calculate_metrics(self):
|
def _calculate_metrics(self):
|
||||||
|
# For open positions, use the last kline price to mark to market
|
||||||
|
# If no last kline price, fall back to entry price
|
||||||
|
position_price = self.last_kline_price
|
||||||
|
if position_price is None and self.trades and self.position > 0:
|
||||||
|
position_price = self.trades[-1]["price"] # Fall back to entry price
|
||||||
|
|
||||||
final_balance = self.current_balance + (
|
final_balance = self.current_balance + (
|
||||||
self.position * self.trades[-1]["price"]
|
self.position * position_price
|
||||||
if self.trades and self.position > 0
|
if self.position > 0 and position_price
|
||||||
else 0
|
else self.current_balance
|
||||||
)
|
)
|
||||||
total_return = (
|
total_return = (
|
||||||
(final_balance - self.initial_balance) / self.initial_balance
|
(final_balance - self.initial_balance) / self.initial_balance
|
||||||
@@ -358,6 +364,11 @@ class BacktestEngine:
|
|||||||
|
|
||||||
portfolio_value = running_balance + (running_position * last_price)
|
portfolio_value = running_balance + (running_position * last_price)
|
||||||
portfolio_values.append(portfolio_value)
|
portfolio_values.append(portfolio_value)
|
||||||
|
|
||||||
|
# If there's an open position, add final marked-to-market value
|
||||||
|
if self.position > 0 and self.last_kline_price:
|
||||||
|
final_portfolio_value = self.current_balance + (self.position * self.last_kline_price)
|
||||||
|
portfolio_values.append(final_portfolio_value)
|
||||||
|
|
||||||
max_value = self.initial_balance
|
max_value = self.initial_balance
|
||||||
max_drawdown = 0.0
|
max_drawdown = 0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user