diegobeyl/backtesting
2
1#!/usr/bin/env python3
2"""
3Quick validation script for Week 1 Implementation
4Tests imports and basic functionality without running full backtest
5"""
6
7import sys
8from pathlib import Path
9
10# Add project root to path
11project_root = Path(__file__).parent
12sys.path.insert(0, str(project_root))
13
14
15def test_imports():
16 """Test that all new modules can be imported"""
17 print("\n" + "="*60)
18 print("TESTING IMPORTS")
19 print("="*60)
20
21 tests = []
22
23 try:
24 from utils.exceptions import (
25 BacktestingException, DataLoadException, ValidationException,
26 AlgorithmException, TimeoutException, ConnectionException
27 )
28 print("✅ utils.exceptions - All 6 exception classes imported")
29 tests.append(True)
30 except Exception as e:
31 print(f"❌ utils.exceptions - FAILED: {e}")
32 tests.append(False)
33
34 try:
35 from utils.validators import InputValidator
36 print("✅ utils.validators - InputValidator imported")
37 tests.append(True)
38 except Exception as e:
39 print(f"❌ utils.validators - FAILED: {e}")
40 tests.append(False)
41
42 try:
43 from utils.timeout import async_timeout, sync_timeout
44 print("✅ utils.timeout - Both decorators imported")
45 tests.append(True)
46 except Exception as e:
47 print(f"❌ utils.timeout - FAILED: {e}")
48 tests.append(False)
49
50 return all(tests)
51
52
53def test_exception_functionality():
54 """Test exception classes work correctly"""
55 print("\n" + "="*60)
56 print("TESTING EXCEPTION FUNCTIONALITY")
57 print("="*60)
58
59 from utils.exceptions import ValidationException, TimeoutException
60
61 tests = []
62
63 try:
64 exc = ValidationException(
65 "Test validation error",
66 field="test_field",
67 expected="int",
68 actual="str"
69 )
70 exc_dict = exc.to_dict()
71 assert exc_dict["error_code"] == "VALIDATION_ERROR"
72 assert "field" in exc_dict["details"]
73 assert exc_dict["details"]["field"] == "test_field"
74 print("✅ ValidationException - to_dict() works correctly")
75 tests.append(True)
76 except Exception as e:
77 import traceback
78 error_msg = f"{e}\n{traceback.format_exc()}"
79 print(f"❌ ValidationException - FAILED: {error_msg}")
80 tests.append(False)
81
82 try:
83 exc = TimeoutException(
84 "Operation timed out",
85 operation="fetch_data",
86 timeout_seconds=30
87 )
88 exc_dict = exc.to_dict()
89 assert exc_dict["error_code"] == "TIMEOUT_ERROR"
90 print("✅ TimeoutException - Works correctly")
91 tests.append(True)
92 except Exception as e:
93 print(f"❌ TimeoutException - FAILED: {e}")
94 tests.append(False)
95
96 return all(tests)
97
98
99def test_validator_basic():
100 """Test InputValidator basic functionality"""
101 print("\n" + "="*60)
102 print("TESTING VALIDATOR FUNCTIONALITY")
103 print("="*60)
104
105 from utils.validators import InputValidator
106 from utils.exceptions import ValidationException
107 import pandas as pd
108
109 tests = []
110
111 # Test symbol validation
112 try:
113 assert InputValidator.validate_symbol("BTCUSD") is True
114 print("✅ InputValidator.validate_symbol() - Valid symbol accepted")
115 tests.append(True)
116 except Exception as e:
117 print(f"❌ InputValidator.validate_symbol() - FAILED: {e}")
118 tests.append(False)
119
120 # Test invalid symbol
121 try:
122 InputValidator.validate_symbol("INVALID@SYMBOL")
123 print("❌ InputValidator.validate_symbol() - Should reject invalid symbols")
124 tests.append(False)
125 except ValidationException:
126 print("✅ InputValidator.validate_symbol() - Correctly rejects invalid symbols")
127 tests.append(True)
128
129 # Test valid DataFrame
130 try:
131 df = pd.DataFrame({
132 'open': [100.0] * 20,
133 'high': [101.0] * 20,
134 'low': [99.0] * 20,
135 'close': [100.5] * 20,
136 'volume': [1000000] * 20
137 })
138 is_valid, error = InputValidator.validate_dataframe(df, "BTCUSD")
139 assert is_valid is True
140 assert error is None
141 print("✅ InputValidator.validate_dataframe() - Valid DataFrame accepted")
142 tests.append(True)
143 except Exception as e:
144 print(f"❌ InputValidator.validate_dataframe() - FAILED: {e}")
145 tests.append(False)
146
147 # Test backtest params
148 try:
149 is_valid, error = InputValidator.validate_backtest_params(
150 initial_capital=10000,
151 risk_percent=2.0,
152 symbol="BTCUSD"
153 )
154 assert is_valid is True
155 print("✅ InputValidator.validate_backtest_params() - Valid params accepted")
156 tests.append(True)
157 except Exception as e:
158 print(f"❌ InputValidator.validate_backtest_params() - FAILED: {e}")
159 tests.append(False)
160
161 return all(tests)
162
163
164def test_timeout_decorator():
165 """Test timeout decorator syntax"""
166 print("\n" + "="*60)
167 print("TESTING TIMEOUT DECORATORS")
168 print("="*60)
169
170 from utils.timeout import async_timeout, sync_timeout
171 import asyncio
172
173 tests = []
174
175 # Test async_timeout decorator
176 try:
177 @async_timeout(5)
178 async def dummy_async():
179 await asyncio.sleep(0.1)
180 return "success"
181
182 print("✅ @async_timeout - Decorator applies correctly")
183 tests.append(True)
184 except Exception as e:
185 print(f"❌ @async_timeout - FAILED: {e}")
186 tests.append(False)
187
188 # Test sync_timeout decorator
189 try:
190 @sync_timeout(5)
191 def dummy_sync():
192 return "success"
193
194 print("✅ @sync_timeout - Decorator applies correctly")
195 tests.append(True)
196 except Exception as e:
197 print(f"❌ @sync_timeout - FAILED: {e}")
198 tests.append(False)
199
200 return all(tests)
201
202
203def test_backtester_imports():
204 """Test that backtester has validation imports"""
205 print("\n" + "="*60)
206 print("TESTING BACKTESTER INTEGRATION")
207 print("="*60)
208
209 tests = []
210
211 try:
212 # Read backtester.py and check for new imports
213 with open(project_root / "backtesting_app" / "core" / "backtester.py", "r") as f:
214 content = f.read()
215
216 # Check for validation import
217 if "from utils.validators import InputValidator" in content:
218 print("✅ backtester.py - Has InputValidator import")
219 tests.append(True)
220 else:
221 print("❌ backtester.py - Missing InputValidator import")
222 tests.append(False)
223
224 # Check for exception imports
225 if "from utils.exceptions import ValidationException, AlgorithmException" in content:
226 print("✅ backtester.py - Has exception imports")
227 tests.append(True)
228 else:
229 print("❌ backtester.py - Missing exception imports")
230 tests.append(False)
231
232 # Check for validation call
233 if "InputValidator.validate_dataframe" in content:
234 print("✅ backtester.py - Calls validate_dataframe()")
235 tests.append(True)
236 else:
237 print("❌ backtester.py - Missing validate_dataframe() call")
238 tests.append(False)
239
240 except Exception as e:
241 print(f"❌ backtester.py - FAILED: {e}")
242 tests.append(False)
243
244 return all(tests)
245
246
247def test_routes_imports():
248 """Test that routes has validation imports"""
249 print("\n" + "="*60)
250 print("TESTING ROUTES INTEGRATION")
251 print("="*60)
252
253 tests = []
254
255 try:
256 # Read routes.py and check for new imports
257 with open(project_root / "api" / "routes.py", "r") as f:
258 content = f.read()
259
260 # Check for validation import
261 if "from utils.validators import InputValidator" in content:
262 print("✅ routes.py - Has InputValidator import")
263 tests.append(True)
264 else:
265 print("❌ routes.py - Missing InputValidator import")
266 tests.append(False)
267
268 # Check for timeout import
269 if "from utils.timeout import async_timeout" in content:
270 print("✅ routes.py - Has async_timeout import")
271 tests.append(True)
272 else:
273 print("❌ routes.py - Missing async_timeout import")
274 tests.append(False)
275
276 # Check for exception imports
277 if "from utils.exceptions import" in content:
278 print("✅ routes.py - Has exception imports")
279 tests.append(True)
280 else:
281 print("❌ routes.py - Missing exception imports")
282 tests.append(False)
283
284 # Check for timeout decorator
285 if "@async_timeout(300)" in content:
286 print("✅ routes.py - Has @async_timeout(300) decorator")
287 tests.append(True)
288 else:
289 print("❌ routes.py - Missing @async_timeout(300) decorator")
290 tests.append(False)
291
292 except Exception as e:
293 print(f"❌ routes.py - FAILED: {e}")
294 tests.append(False)
295
296 return all(tests)
297
298
299def main():
300 """Run all validation tests"""
301 print("\n" + "="*60)
302 print("WEEK 1 IMPLEMENTATION VALIDATION")
303 print("="*60)
304
305 results = {
306 "Imports": test_imports(),
307 "Exceptions": test_exception_functionality(),
308 "Validators": test_validator_basic(),
309 "Timeouts": test_timeout_decorator(),
310 "Backtester Integration": test_backtester_imports(),
311 "Routes Integration": test_routes_imports(),
312 }
313
314 print("\n" + "="*60)
315 print("SUMMARY")
316 print("="*60)
317
318 passed = sum(1 for v in results.values() if v)
319 total = len(results)
320
321 for test_name, result in results.items():
322 status = "✅ PASS" if result else "❌ FAIL"
323 print(f"{test_name:30} {status}")
324
325 print(f"\nTotal: {passed}/{total} test suites passed")
326
327 if passed == total:
328 print("\n🎉 ALL TESTS PASSED - Week 1 implementation is ready!")
329 return 0
330 else:
331 print(f"\n⚠️ {total - passed} test suite(s) failed - Check output above")
332 return 1
333
334
335if __name__ == "__main__":
336 sys.exit(main())
337 