-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.py
More file actions
253 lines (203 loc) · 9 KB
/
Copy pathmain.py
File metadata and controls
253 lines (203 loc) · 9 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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
"""Main entry point for Futu AI Trading System."""
import sys
import signal
import schedule
import time
from datetime import datetime
from config.settings import Settings
from data.futu_client import FutuClient
from data.news_collector import NewsCollector
from core.ai_analyzer import AIAnalyzer
from core.rule_engine import RuleEngine
from core.portfolio_manager import PortfolioManager
from utils.logger import get_system_logger
from utils.notification import NotificationService
logger = get_system_logger()
class TradingSystem:
"""Main trading system orchestrator."""
def __init__(self):
"""Initialize the trading system."""
self.running = False
self.futu_client = None
self.portfolio_manager = None
# Setup signal handlers for graceful shutdown
signal.signal(signal.SIGINT, self._signal_handler)
signal.signal(signal.SIGTERM, self._signal_handler)
def _signal_handler(self, signum, frame):
"""Handle shutdown signals."""
logger.info("Shutdown signal received, stopping trading system...")
self.shutdown()
sys.exit(0)
def initialize(self):
"""Initialize all components."""
logger.info("="*60)
logger.info("Initializing Futu AI Trading System")
logger.info("="*60)
try:
# Validate configuration
logger.info("Validating configuration...")
Settings.validate()
logger.info(Settings.display())
# Initialize components
logger.info("Initializing components...")
# Futu client
logger.info("Connecting to Futu OpenD...")
self.futu_client = FutuClient(Settings)
# News collector
logger.info("Initializing news collector...")
news_collector = NewsCollector()
# AI analyzer
logger.info("Initializing AI analyzer...")
ai_analyzer = AIAnalyzer(Settings)
# Rule engine
logger.info("Initializing rule engine...")
rule_engine = RuleEngine(Settings)
# Notification service
logger.info("Initializing notification service...")
notification = NotificationService(Settings)
# Portfolio manager
logger.info("Initializing portfolio manager...")
self.portfolio_manager = PortfolioManager(
futu_client=self.futu_client,
ai_analyzer=ai_analyzer,
rule_engine=rule_engine,
news_collector=news_collector,
notification=notification,
settings=Settings
)
logger.info("="*60)
logger.info("System initialized successfully")
logger.info("="*60)
# Send startup notification
notification.send_alert(
"Trading System Started",
f"Futu AI Trading System started in {Settings.TRADING_MODE} mode\n"
f"Watchlist: {', '.join(Settings.WATCHLIST)}",
level='INFO'
)
return True
except Exception as e:
logger.error(f"Failed to initialize system: {e}", exc_info=True)
return False
def setup_schedule(self):
"""Setup scheduled tasks."""
logger.info("Setting up scheduled tasks...")
# Daily analysis after HK market close (16:30 HKT)
schedule.every().day.at("16:30").do(self._run_daily_analysis)
# Weekly report on Monday morning (09:00 HKT)
schedule.every().monday.at("09:00").do(self._generate_weekly_report)
# Quarterly rebalancing (first day of quarter at 17:00)
schedule.every().day.at("17:00").do(self._check_quarterly_rebalancing)
# Clean old news weekly
schedule.every().sunday.at("02:00").do(self._clean_old_news)
# Refresh news every 5 minutes
schedule.every(5).minutes.do(self._refresh_news)
logger.info("Scheduled tasks:")
logger.info(" - Daily analysis: 16:30 (after market close)")
logger.info(" - Weekly report: Monday 09:00")
logger.info(" - Quarterly rebalancing check: Daily 17:00")
logger.info(" - News cleanup: Sunday 02:00")
logger.info(" - News refresh: Every 5 minutes")
def _run_daily_analysis(self):
"""Wrapper for daily analysis with error handling."""
try:
logger.info("\n" + "="*60)
logger.info(f"Scheduled daily analysis triggered at {datetime.now()}")
logger.info("="*60 + "\n")
self.portfolio_manager.run_daily_analysis()
except Exception as e:
logger.error(f"Error in scheduled daily analysis: {e}", exc_info=True)
def _generate_weekly_report(self):
"""Generate and send weekly report."""
try:
logger.info("Generating weekly report...")
report = self.portfolio_manager.generate_report()
logger.info("Weekly report generated")
except Exception as e:
logger.error(f"Error generating weekly report: {e}", exc_info=True)
def _check_quarterly_rebalancing(self):
"""Check if quarterly rebalancing is needed."""
try:
now = datetime.now()
# Rebalance on first day of quarter
if now.day == 1 and now.month in [1, 4, 7, 10]:
logger.info("Quarterly rebalancing triggered")
self.portfolio_manager.rebalance_portfolio()
except Exception as e:
logger.error(f"Error in quarterly rebalancing: {e}", exc_info=True)
def _clean_old_news(self):
"""Clean old news from database."""
try:
logger.info("Cleaning old news...")
news_collector = NewsCollector()
deleted = news_collector.clean_old_news(days_to_keep=30)
logger.info(f"Cleaned {deleted} old news articles")
except Exception as e:
logger.error(f"Error cleaning old news: {e}", exc_info=True)
def _refresh_news(self):
"""Refresh news from RSS feeds."""
try:
news_collector = NewsCollector()
new_count = news_collector.fetch_latest_news(hours_back=1)
logger.info(f"News refresh completed: {new_count} new articles")
except Exception as e:
logger.error(f"Error refreshing news: {e}", exc_info=True)
def run(self):
"""Start the main event loop."""
logger.info("="*60)
logger.info("Starting Trading System Event Loop")
logger.info("="*60)
logger.info("Press Ctrl+C to stop")
logger.info("")
self.running = True
# Run initial analysis if market is closed
hour = datetime.now().hour
if hour >= 17 or hour < 9: # After market close or before market open
logger.info("Running initial analysis...")
try:
self.portfolio_manager.run_daily_analysis()
except Exception as e:
logger.error(f"Error in initial analysis: {e}", exc_info=True)
# Main event loop
while self.running:
try:
schedule.run_pending()
time.sleep(60) # Check every minute
except KeyboardInterrupt:
logger.info("KeyboardInterrupt received")
break
except Exception as e:
logger.error(f"Error in main loop: {e}", exc_info=True)
time.sleep(60)
def shutdown(self):
"""Gracefully shutdown the system."""
logger.info("Shutting down trading system...")
self.running = False
# Close Futu connections
if self.futu_client:
self.futu_client.close()
logger.info("Trading system shutdown complete")
def main():
"""Main entry point."""
print("""
╔═══════════════════════════════════════════════════════════╗
║ Futu AI Trading System ║
║ Powered by Ollama ║
╚═══════════════════════════════════════════════════════════╝
""")
# Create and initialize system
system = TradingSystem()
if not system.initialize():
logger.error("Failed to initialize system. Exiting.")
sys.exit(1)
# Setup scheduled tasks
system.setup_schedule()
# Start main loop
try:
system.run()
except Exception as e:
logger.error(f"Fatal error: {e}", exc_info=True)
system.shutdown()
sys.exit(1)
if __name__ == "__main__":
main()