This commit is contained in:
Oleg Sheynin
2025-07-22 17:25:16 +00:00
parent 0e83142d0a
commit 31eb9f800c
7 changed files with 75 additions and 77 deletions
+44 -47
View File
@@ -442,11 +442,13 @@ class BacktestResult:
self,
pair_nm: str,
symbol: str,
side: str,
action: str,
price: Any,
disequilibrium: Optional[float] = None,
scaled_disequilibrium: Optional[float] = None,
timestamp: Optional[datetime] = None,
status: Optional[str] = None,
) -> None:
"""Add a trade to the results tracking."""
pair_nm = str(pair_nm)
@@ -456,7 +458,15 @@ class BacktestResult:
if symbol not in self.trades[pair_nm]:
self.trades[pair_nm][symbol] = []
self.trades[pair_nm][symbol].append(
(action, price, disequilibrium, scaled_disequilibrium, timestamp)
{"symbol":symbol,
"side":side,
"action":action,
"price":price,
"disequilibrium":disequilibrium,
"scaled_disequilibrium":scaled_disequilibrium,
"timestamp":timestamp,
"status":status
}
)
def add_outstanding_position(self, position: Dict[str, Any]) -> None:
@@ -493,6 +503,7 @@ class BacktestResult:
print(result)
for row in result.itertuples():
side = row.side
action = row.action
symbol = row.symbol
price = row.price
@@ -502,15 +513,17 @@ class BacktestResult:
timestamp = getattr(row, "time")
else:
timestamp = convert_timestamp(row.Index)
status = row.status
self.add_trade(
pair_nm=str(row.pair),
action=str(action),
symbol=str(symbol),
side=str(side),
action=str(action),
price=float(str(price)),
disequilibrium=disequilibrium,
scaled_disequilibrium=scaled_disequilibrium,
timestamp=timestamp,
status=str(status) if status is not None else "?",
)
def print_single_day_results(self) -> None:
@@ -553,42 +566,22 @@ class BacktestResult:
for symbol, trades in symbols.items():
if len(trades) == 0:
continue
symbol_return = 0
symbol_trades = []
# Process all trades sequentially for this symbol
for i, trade in enumerate(trades):
# Handle both old and new tuple formats
if len(trade) == 2: # Old format: (action, price)
action, price = trade
disequilibrium = None
scaled_disequilibrium = None
timestamp = None
else: # New format: (action, price, disequilibrium, scaled_disequilibrium, timestamp)
action, price = trade[:2]
disequilibrium = trade[2] if len(trade) > 2 else None
scaled_disequilibrium = trade[3] if len(trade) > 3 else None
timestamp = trade[4] if len(trade) > 4 else None
symbol_trades.append((action, price, disequilibrium, scaled_disequilibrium, timestamp))
symbol_trades = [trade for trade in trades if trade["symbol"] == symbol]
# Calculate returns for all trade combinations
for i in range(len(symbol_trades) - 1):
trade1 = symbol_trades[i]
trade2 = symbol_trades[i + 1]
action1, price1, diseq1, scaled_diseq1, ts1 = trade1
action2, price2, diseq2, scaled_diseq2, ts2 = trade2
trade1 = trades[i]
trade2 = trades[i + 1]
# Calculate return based on action combination
trade_return = 0
if action1 == "BUY" and action2 == "SELL":
if trade1["side"] == "BUY" and trade2["side"] == "SELL":
# Long position
trade_return = (price2 - price1) / price1 * 100
elif action1 == "SELL" and action2 == "BUY":
trade_return = (trade2["price"] - trade1["price"]) / trade1["price"] * 100
elif trade1["side"] == "SELL" and trade2["side"] == "BUY":
# Short position
trade_return = (price1 - price2) / price1 * 100
trade_return = (trade1["price"] - trade2["price"]) / trade1["price"] * 100
symbol_return += trade_return
@@ -596,13 +589,13 @@ class BacktestResult:
pair_trades.append(
(
symbol,
action1,
price1,
action2,
price2,
trade1["side"],
trade1["price"],
trade2["side"],
trade2["price"],
trade_return,
scaled_diseq1,
scaled_diseq2,
trade1["scaled_disequilibrium"],
trade2["scaled_disequilibrium"],
i + 1, # Trade sequence number
)
)
@@ -614,24 +607,28 @@ class BacktestResult:
print(f" {pair}:")
for (
symbol,
action1,
price1,
action2,
price2,
trade1["side"],
trade1["price"],
trade2["side"],
trade2["price"],
trade_return,
scaled_diseq1,
scaled_diseq2,
trade1["scaled_disequilibrium"],
trade2["scaled_disequilibrium"],
trade_num,
) in pair_trades:
disequil_info = ""
if (
scaled_diseq1 is not None
and scaled_diseq2 is not None
trade1["scaled_disequilibrium"] is not None
and trade2["scaled_disequilibrium"] is not None
):
disequil_info = f" | Open Dis-eq: {scaled_diseq1:.2f}, Close Dis-eq: {scaled_diseq2:.2f}"
disequil_info = f" | Open Dis-eq: {trade1["scaled_disequilibrium"]:.2f},"
f" Close Dis-eq: {trade2["scaled_disequilibrium"]:.2f}"
print(
f" {symbol} (Trade #{trade_num}): {action1} @ ${price1:.2f}, {action2} @ ${price2:.2f}, Return: {trade_return:.2f}%{disequil_info}"
f" {symbol} (Trade #{trade_num}):"
f" {trade1["side"]} @ ${trade1["price"]:.2f},"
f" {trade2["side"]} @ ${trade2["price"]:.2f},"
f" Return: {trade_return:.2f}%{disequil_info}"
)
print(f" Pair Total Return: {pair_return:.2f}%")
day_return += pair_return