-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest_backtest_minimal.py
More file actions
196 lines (155 loc) · 6.47 KB
/
test_backtest_minimal.py
File metadata and controls
196 lines (155 loc) · 6.47 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
"""
Minimal backtest test script that uses mocked data to avoid database connectivity issues.
"""
import logging
from datetime import datetime, timedelta
import numpy as np
import pandas as pd
from src.backtesting.backtester import StrategyBacktester
# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger("test_backtest")
def create_mock_data(start_date, end_date, interval="1d"):
"""Create mock price data for testing."""
# Generate dates - make them timezone-naive to match the backtester
if interval == "1d":
dates = pd.date_range(start=start_date, end=end_date, freq="D")
else:
dates = pd.date_range(start=start_date, end=end_date, freq="H")
# Convert to timezone-naive
dates = dates.tz_localize(None)
# Generate mock price data with some randomness but overall uptrend
n = len(dates)
base_price = 50000
trend = np.linspace(0, 20000, n) # Overall uptrend
noise = np.random.normal(0, 2000, n) # Random noise
prices = base_price + trend + noise
# Create DataFrame with OHLCV data
df = pd.DataFrame(
{
"timestamp": dates,
"close": prices,
"open": prices * 0.99, # Slightly lower than close
"high": prices * 1.02, # Slightly higher than close
"low": prices * 0.98, # Slightly lower than close
"volume": np.random.normal(1000000, 200000, n), # Random volume
"market_cap_usd": prices * 19000000, # Approximate market cap
"price_change_24h_pct": np.random.normal(0, 2, n), # Random daily change
"asset_id": 1, # Mock asset ID for BTC
"id": range(1, n + 1), # Mock record IDs
}
)
# Set timestamp as index
df.set_index("timestamp", inplace=True)
return df
class MockDatabaseClient:
"""Mock database client that returns pre-generated data."""
def __init__(self, mock_data):
self.mock_data = mock_data
def get_asset_prices(
self, asset_id, limit=500, order_by=None, start_time=None, end_time=None
):
"""Return mock price data."""
if start_time and end_time:
filtered_data = self.mock_data[
(self.mock_data.index >= start_time)
& (self.mock_data.index <= end_time)
]
elif start_time:
filtered_data = self.mock_data[self.mock_data.index >= start_time]
elif end_time:
filtered_data = self.mock_data[self.mock_data.index <= end_time]
else:
filtered_data = self.mock_data
if limit:
filtered_data = filtered_data.tail(limit)
# Convert to records format expected by backtester
return filtered_data.reset_index().to_dict("records")
def get_asset_by_symbol(self, symbol):
"""Return mock asset data."""
if symbol == "BTC":
return [{"id": 1, "symbol": "BTC", "name": "Bitcoin"}]
return []
def get_market_data(
self, asset_id, start_date=None, end_date=None, interval=None, limit=None
):
"""Mock implementation of get_market_data"""
start_time = start_date
end_time = end_date
if start_time and end_time:
filtered_data = self.mock_data[
(self.mock_data.index >= start_time)
& (self.mock_data.index <= end_time)
]
elif start_time:
filtered_data = self.mock_data[self.mock_data.index >= start_time]
elif end_time:
filtered_data = self.mock_data[self.mock_data.index <= end_time]
else:
filtered_data = self.mock_data
if limit:
filtered_data = filtered_data.tail(limit)
return filtered_data
def get_historical_market_data_df(
self, asset_id, start_date=None, end_date=None, days_history=None, interval=None
):
"""Mock implementation of get_historical_market_data_df"""
start_time = start_date
end_time = end_date
if days_history and start_time is None:
start_time = datetime.now() - timedelta(days=days_history)
return self.get_market_data(
asset_id, start_date=start_time, end_date=end_time, interval=interval
)
def insert_prediction(self, prediction_data):
"""Mock prediction insertion."""
logger.info(f"Mock inserted prediction: {prediction_data}")
return True
def run_minimal_backtest():
"""Run a minimal backtest with mocked data."""
# Define backtest period - make timezone-aware to match data
start_date = datetime(2024, 10, 1)
end_date = datetime(2025, 3, 1)
# Create mock data
logger.info("Generating mock price data...")
mock_data = create_mock_data(start_date - timedelta(days=100), end_date)
# Create mock database client
mock_db = MockDatabaseClient(mock_data)
# Monkey patch the backtester to handle timezone conversion
original_load_historical_data = StrategyBacktester.load_historical_data
def patched_load_historical_data(self, asset_id):
"""Patched version that ensures timezone compatibility"""
data = original_load_historical_data(self, asset_id)
# Make the index timezone-naive if it's timezone-aware
if hasattr(data.index, "tz") and data.index.tz is not None:
data.index = data.index.tz_localize(None)
return data
# Apply the monkey patch
StrategyBacktester.load_historical_data = patched_load_historical_data
# Initialize backtester with mock database
logger.info("Initializing backtester...")
backtester = StrategyBacktester(
start_date=start_date,
end_date=end_date,
assets=["BTC"],
interval="1d",
prediction_timeframe="24h",
use_sentiment=False,
db_client=mock_db,
)
# Monkey patch the backtester to use our mock database
backtester.db_client = mock_db
# Run backtest
logger.info("Running backtest...")
results = backtester.run_backtest(step_size=timedelta(days=1))
# Print results
logger.info("Backtest completed!")
logger.info(f"Total predictions: {results.get('total_predictions', 0)}")
logger.info(f"Correct predictions: {results.get('correct_predictions', 0)}")
logger.info(f"Accuracy: {results.get('accuracy', 0):.2f}%")
logger.info(f"Overall profit/loss: {results.get('overall_pnl', 0):.2f}%")
return results
if __name__ == "__main__":
run_minimal_backtest()