-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbacktester.py
More file actions
114 lines (95 loc) · 3.81 KB
/
backtester.py
File metadata and controls
114 lines (95 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import asyncio
from json.tool import main
from utils.order_book import OrderBook
from utils.OB_snapshot_reader import OrderBookSnapshotReader
from utils.backtesting_engine import BacktestingEngine
from utils.portfolio_tracker import PortfolioTracker
from Strats.strategy_runner import StrategyRunner
from Strats.ob_imbalance import OrderBookImbalanceStrategy
class Backtester:
"""Backtester for trading strategies using historical data"""
def __init__(self, data_file: str = "order_book.json",
initial_cash: float = 100000.0,
commission_rate: float = 0.0,
delay: float = 1.0):
self.data_file = data_file
self.initial_cash = initial_cash
self.commission_rate = commission_rate
self.delay = delay
self.portfolio_tracker = None
async def load_data(self):
pass
async def run_backtest(self):
# Create queues
orderbook_q = asyncio.Queue()
signal_q = asyncio.Queue()
# Create portfolio tracker
self.portfolio_tracker = PortfolioTracker(
initial_cash=self.initial_cash,
commission_rate=self.commission_rate
)
# Create strategy
strategy = OrderBookImbalanceStrategy()
strategy.initialize()
# Create orderbook
order_book = OrderBook(symbol=strategy.symbol, max_levels=10, trim_frequency=10)
# Create components
data_feed = OrderBookSnapshotReader(
filepath=self.data_file,
order_book=order_book,
out_q=orderbook_q,
delay=0,
verbose=True
)
strategy_runner = StrategyRunner(
in_q=orderbook_q,
out_q=signal_q,
strategy=strategy,
)
exec_engine = BacktestingEngine(
in_q=signal_q,
portfolio_tracker=self.portfolio_tracker
)
# Create tasks
tasks = [
asyncio.create_task(data_feed.connect(), name="data_feed"),
asyncio.create_task(strategy_runner.run(), name="strategy"),
asyncio.create_task(exec_engine.run(), name="execution"),
]
try:
await asyncio.gather(*tasks)
except KeyboardInterrupt:
print("\nShutting down...", flush=True)
finally:
# Cancel all tasks
for task in tasks:
task.cancel()
# Wait for tasks to finish cancellation
await asyncio.gather(*tasks, return_exceptions=True)
# Stop data feed
data_feed.running = False
# Print backtest results
self._print_results()
def _print_results(self):
"""Print backtest results and export data"""
if self.portfolio_tracker:
print("\n" + "="*60)
print("BACKTEST COMPLETED")
print("="*60)
# Print summary
self.portfolio_tracker.print_summary()
# Export results
try:
self.portfolio_tracker.export_results("./backtest_results")
print("Results exported to ./backtest_results/")
except Exception as e:
print(f"Error exporting results: {e}")
# Try to plot (will fail if matplotlib not installed)
try:
self.portfolio_tracker.plot_portfolio_value("./backtest_results/portfolio_chart.png")
self.portfolio_tracker.plot_prices("./backtest_results/price_chart.png")
except Exception as e:
print(f"Could not generate plots (install matplotlib): {e}")
if __name__ == "__main__":
backtest = Backtester()
asyncio.run(backtest.run_backtest())