Edwin Salguero commited on
Commit
9f44dc9
Β·
1 Parent(s): f820bf2

feat(ui): add robust multi-interface UI system (Streamlit, Dash, Jupyter, WebSocket) with launcher, docs, and integration tests [skip ci]

Browse files
README.md CHANGED
@@ -23,6 +23,13 @@ A sophisticated algorithmic trading system that combines reinforcement learning
23
  - **Account Management**: Portfolio monitoring and position tracking
24
  - **Order Types**: Market orders, limit orders, and order cancellation
25
 
 
 
 
 
 
 
 
26
  ### Advanced Features
27
  - **Docker Support**: Containerized deployment for consistency
28
  - **Comprehensive Logging**: Detailed logs for debugging and performance analysis
@@ -100,7 +107,22 @@ finrl:
100
 
101
  ## πŸš€ Quick Start
102
 
103
- ### 1. Run the Demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  ```bash
105
  python demo.py
106
  ```
@@ -111,12 +133,12 @@ This will:
111
  - Show trading workflow execution
112
  - Run backtesting on historical data
113
 
114
- ### 2. Start Paper Trading
115
  ```bash
116
  python -m agentic_ai_system.main --mode live --duration 60
117
  ```
118
 
119
- ### 3. Run Backtesting
120
  ```bash
121
  python -m agentic_ai_system.main --mode backtest --start-date 2024-01-01 --end-date 2024-01-31
122
  ```
@@ -262,6 +284,13 @@ algorithmic_trading/
262
  β”‚ β”œβ”€β”€ πŸ“„ synthetic_data_generator.py # Test data generation
263
  β”‚ └── πŸ“„ logger_config.py # Logging configuration
264
  β”‚
 
 
 
 
 
 
 
265
  β”œβ”€β”€ πŸ§ͺ tests/ # Test suite
266
  β”‚ β”œβ”€β”€ πŸ“„ __init__.py
267
  β”‚ β”œβ”€β”€ πŸ“„ test_data_ingestion.py
@@ -293,6 +322,8 @@ algorithmic_trading/
293
  β”‚
294
  β”œβ”€β”€ πŸ“„ demo.py # Main demo script
295
  β”œβ”€β”€ πŸ“„ finrl_demo.py # FinRL-specific demo
 
 
296
  β”œβ”€β”€ πŸ“„ DOCKER_HUB_SETUP.md # Docker Hub documentation
297
  β”‚
298
  └── 🐍 .venv/ # Python virtual environment
@@ -362,6 +393,54 @@ risk:
362
  take_profit: 0.05
363
  ```
364
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  ## πŸ“ˆ Performance Monitoring
366
 
367
  ### Logging
 
23
  - **Account Management**: Portfolio monitoring and position tracking
24
  - **Order Types**: Market orders, limit orders, and order cancellation
25
 
26
+ ### 🎨 Comprehensive UI System
27
+ - **Streamlit UI**: Quick prototyping and data science workflows
28
+ - **Dash UI**: Enterprise-grade interactive dashboards
29
+ - **Jupyter UI**: Interactive notebook-based interfaces
30
+ - **WebSocket API**: Real-time trading data streaming
31
+ - **Multi-interface Support**: Choose the right UI for your needs
32
+
33
  ### Advanced Features
34
  - **Docker Support**: Containerized deployment for consistency
35
  - **Comprehensive Logging**: Detailed logs for debugging and performance analysis
 
107
 
108
  ## πŸš€ Quick Start
109
 
110
+ ### 1. Launch the UI (Recommended)
111
+ ```bash
112
+ # Launch Streamlit UI (best for beginners)
113
+ python ui_launcher.py streamlit
114
+
115
+ # Launch Dash UI (best for production)
116
+ python ui_launcher.py dash
117
+
118
+ # Launch Jupyter Lab
119
+ python ui_launcher.py jupyter
120
+
121
+ # Launch all UIs
122
+ python ui_launcher.py all
123
+ ```
124
+
125
+ ### 2. Run the Demo
126
  ```bash
127
  python demo.py
128
  ```
 
133
  - Show trading workflow execution
134
  - Run backtesting on historical data
135
 
136
+ ### 3. Start Paper Trading
137
  ```bash
138
  python -m agentic_ai_system.main --mode live --duration 60
139
  ```
140
 
141
+ ### 4. Run Backtesting
142
  ```bash
143
  python -m agentic_ai_system.main --mode backtest --start-date 2024-01-01 --end-date 2024-01-31
144
  ```
 
284
  β”‚ β”œβ”€β”€ πŸ“„ synthetic_data_generator.py # Test data generation
285
  β”‚ └── πŸ“„ logger_config.py # Logging configuration
286
  β”‚
287
+ β”œβ”€β”€ 🎨 ui/ # User interface system
288
+ β”‚ β”œβ”€β”€ πŸ“„ __init__.py # UI package initialization
289
+ β”‚ β”œβ”€β”€ πŸ“„ streamlit_app.py # Streamlit web application
290
+ β”‚ β”œβ”€β”€ πŸ“„ dash_app.py # Dash enterprise dashboard
291
+ β”‚ β”œβ”€β”€ πŸ“„ jupyter_widgets.py # Jupyter interactive widgets
292
+ β”‚ └── πŸ“„ websocket_server.py # Real-time WebSocket server
293
+ β”‚
294
  β”œβ”€β”€ πŸ§ͺ tests/ # Test suite
295
  β”‚ β”œβ”€β”€ πŸ“„ __init__.py
296
  β”‚ β”œβ”€β”€ πŸ“„ test_data_ingestion.py
 
322
  β”‚
323
  β”œβ”€β”€ πŸ“„ demo.py # Main demo script
324
  β”œβ”€β”€ πŸ“„ finrl_demo.py # FinRL-specific demo
325
+ β”œβ”€β”€ πŸ“„ ui_launcher.py # UI launcher script
326
+ β”œβ”€β”€ πŸ“„ UI_SETUP.md # UI setup documentation
327
  β”œβ”€β”€ πŸ“„ DOCKER_HUB_SETUP.md # Docker Hub documentation
328
  β”‚
329
  └── 🐍 .venv/ # Python virtual environment
 
393
  take_profit: 0.05
394
  ```
395
 
396
+ ## 🎨 User Interface System
397
+
398
+ The project includes a comprehensive UI system with multiple interface options:
399
+
400
+ ### Available UIs
401
+
402
+ #### **Streamlit UI** (Recommended for beginners)
403
+ - **URL**: http://localhost:8501
404
+ - **Features**: Interactive widgets, real-time data visualization, easy configuration
405
+ - **Best for**: Data scientists, quick experiments, rapid prototyping
406
+
407
+ #### **Dash UI** (Recommended for production)
408
+ - **URL**: http://localhost:8050
409
+ - **Features**: Enterprise-grade dashboards, advanced charts, professional styling
410
+ - **Best for**: Production dashboards, real-time monitoring, complex analytics
411
+
412
+ #### **Jupyter UI** (For research)
413
+ - **URL**: http://localhost:8888
414
+ - **Features**: Interactive notebooks, code execution, rich documentation
415
+ - **Best for**: Research, experimentation, educational purposes
416
+
417
+ #### **WebSocket API** (For developers)
418
+ - **URL**: ws://localhost:8765
419
+ - **Features**: Real-time data streaming, trading signals, portfolio updates
420
+ - **Best for**: Real-time trading signals, live data streaming
421
+
422
+ ### Quick UI Launch
423
+ ```bash
424
+ # Launch individual UIs
425
+ python ui_launcher.py streamlit # Streamlit UI
426
+ python ui_launcher.py dash # Dash UI
427
+ python ui_launcher.py jupyter # Jupyter Lab
428
+ python ui_launcher.py websocket # WebSocket server
429
+
430
+ # Launch all UIs at once
431
+ python ui_launcher.py all
432
+ ```
433
+
434
+ ### UI Features
435
+ - **Real-time Data Visualization**: Live market data charts and indicators
436
+ - **Portfolio Monitoring**: Real-time portfolio value and P&L tracking
437
+ - **Trading Controls**: Start/stop trading, backtesting, risk management
438
+ - **FinRL Training**: Interactive model training and evaluation
439
+ - **Alpaca Integration**: Account management and order execution
440
+ - **Configuration Management**: Easy parameter tuning and strategy setup
441
+
442
+ For detailed UI documentation, see [UI_SETUP.md](UI_SETUP.md).
443
+
444
  ## πŸ“ˆ Performance Monitoring
445
 
446
  ### Logging
UI_SETUP.md ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # UI Integration Guide
2
+
3
+ This guide covers the comprehensive UI system for the Algorithmic Trading project, providing multiple interface options for different use cases.
4
+
5
+ ## 🎯 UI Options Overview
6
+
7
+ ### 1. **Streamlit UI** - Quick Prototyping
8
+ - **Best for**: Data scientists, quick experiments, rapid prototyping
9
+ - **Features**: Interactive widgets, real-time data visualization, easy configuration
10
+ - **Port**: 8501
11
+ - **URL**: http://localhost:8501
12
+
13
+ ### 2. **Dash UI** - Enterprise Dashboards
14
+ - **Best for**: Production dashboards, real-time monitoring, complex analytics
15
+ - **Features**: Advanced charts, real-time updates, professional styling
16
+ - **Port**: 8050
17
+ - **URL**: http://localhost:8050
18
+
19
+ ### 3. **Jupyter UI** - Interactive Notebooks
20
+ - **Best for**: Research, experimentation, educational purposes
21
+ - **Features**: Interactive widgets, code execution, rich documentation
22
+ - **Port**: 8888
23
+ - **URL**: http://localhost:8888
24
+
25
+ ### 4. **WebSocket Server** - Real-time Data
26
+ - **Best for**: Real-time trading signals, live data streaming
27
+ - **Features**: WebSocket API, real-time updates, trading signals
28
+ - **Port**: 8765
29
+ - **URL**: ws://localhost:8765
30
+
31
+ ## πŸš€ Quick Start
32
+
33
+ ### Prerequisites
34
+ ```bash
35
+ # Install UI dependencies
36
+ pip install -r requirements.txt
37
+
38
+ # Verify installation
39
+ python -c "import streamlit, dash, plotly, ipywidgets; print('βœ… All UI dependencies installed')"
40
+ ```
41
+
42
+ ### Launch Individual UIs
43
+
44
+ #### Streamlit (Recommended for beginners)
45
+ ```bash
46
+ python ui_launcher.py streamlit
47
+ ```
48
+
49
+ #### Dash (Recommended for production)
50
+ ```bash
51
+ python ui_launcher.py dash
52
+ ```
53
+
54
+ #### Jupyter Lab
55
+ ```bash
56
+ python ui_launcher.py jupyter
57
+ ```
58
+
59
+ #### WebSocket Server
60
+ ```bash
61
+ python ui_launcher.py websocket
62
+ ```
63
+
64
+ #### Launch All UIs
65
+ ```bash
66
+ python ui_launcher.py all
67
+ ```
68
+
69
+ ## πŸ“Š Streamlit UI Features
70
+
71
+ ### Dashboard
72
+ - **System Status**: Real-time trading status, portfolio value, P&L
73
+ - **Configuration Management**: Load and modify trading parameters
74
+ - **Quick Actions**: One-click data loading, Alpaca connection, model training
75
+
76
+ ### Data Ingestion
77
+ - **Multiple Sources**: CSV, Alpaca API, Synthetic data
78
+ - **Data Validation**: Automatic data quality checks
79
+ - **Technical Indicators**: Automatic calculation of moving averages, RSI, MACD
80
+ - **Interactive Charts**: Candlestick, line, volume charts with Plotly
81
+
82
+ ### Alpaca Integration
83
+ - **Account Connection**: Secure API key management
84
+ - **Market Status**: Real-time market hours and status
85
+ - **Position Monitoring**: Current positions and portfolio value
86
+ - **Order Management**: Buy/sell order execution
87
+
88
+ ### FinRL Training
89
+ - **Algorithm Selection**: PPO, A2C, DDPG, TD3
90
+ - **Hyperparameter Tuning**: Learning rate, batch size, training steps
91
+ - **Training Progress**: Real-time training metrics and progress
92
+ - **Model Evaluation**: Performance metrics and backtesting
93
+
94
+ ### Trading Controls
95
+ - **Live Trading**: Start/stop live trading with Alpaca
96
+ - **Backtesting**: Historical strategy testing
97
+ - **Risk Management**: Position sizing and drawdown limits
98
+ - **Emergency Stop**: Immediate trading halt
99
+
100
+ ### Portfolio Monitoring
101
+ - **Real-time Portfolio**: Live portfolio value and P&L
102
+ - **Position Analysis**: Individual position performance
103
+ - **Allocation Charts**: Portfolio allocation visualization
104
+ - **Risk Metrics**: Sharpe ratio, drawdown analysis
105
+
106
+ ## πŸ“ˆ Dash UI Features
107
+
108
+ ### Enterprise Dashboard
109
+ - **Professional Styling**: Bootstrap themes and responsive design
110
+ - **Real-time Updates**: Live data streaming and updates
111
+ - **Advanced Charts**: Interactive Plotly charts with zoom, pan, hover
112
+ - **Multi-page Navigation**: Tabbed interface for different functions
113
+
114
+ ### Advanced Analytics
115
+ - **Technical Analysis**: Advanced charting with indicators
116
+ - **Performance Metrics**: Comprehensive trading performance analysis
117
+ - **Risk Management**: Advanced risk monitoring and alerts
118
+ - **Strategy Comparison**: Multiple strategy backtesting and comparison
119
+
120
+ ### Real-time Monitoring
121
+ - **Live Trading Activity**: Real-time trade execution monitoring
122
+ - **System Alerts**: Automated alerts for important events
123
+ - **Portfolio Tracking**: Live portfolio updates and analysis
124
+ - **Market Data**: Real-time market data visualization
125
+
126
+ ## πŸ““ Jupyter UI Features
127
+
128
+ ### Interactive Development
129
+ - **Widget-based Interface**: Interactive controls for all functions
130
+ - **Code Execution**: Direct Python code execution and experimentation
131
+ - **Data Exploration**: Interactive data analysis and visualization
132
+ - **Model Development**: Iterative model training and testing
133
+
134
+ ### Research Tools
135
+ - **Notebook Integration**: Rich documentation and code examples
136
+ - **Data Analysis**: Pandas and NumPy integration
137
+ - **Visualization**: Matplotlib, Seaborn, Plotly integration
138
+ - **Experiment Tracking**: Training history and model comparison
139
+
140
+ ## πŸ”Œ WebSocket API
141
+
142
+ ### Real-time Data Streaming
143
+ ```javascript
144
+ // Connect to WebSocket server
145
+ const ws = new WebSocket('ws://localhost:8765');
146
+
147
+ // Listen for market data updates
148
+ ws.onmessage = function(event) {
149
+ const data = JSON.parse(event.data);
150
+
151
+ if (data.type === 'market_data') {
152
+ console.log('Price:', data.price);
153
+ console.log('Volume:', data.volume);
154
+ }
155
+
156
+ if (data.type === 'trading_signal') {
157
+ console.log('Signal:', data.signal);
158
+ }
159
+
160
+ if (data.type === 'portfolio_update') {
161
+ console.log('Portfolio:', data.account);
162
+ }
163
+ };
164
+ ```
165
+
166
+ ### Available Message Types
167
+ - `market_data`: Real-time price and volume data
168
+ - `trading_signal`: FinRL model trading signals
169
+ - `portfolio_update`: Account and position updates
170
+ - `trading_status`: Trading system status
171
+ - `system_alert`: System alerts and notifications
172
+
173
+ ## πŸ› οΈ Configuration
174
+
175
+ ### Environment Variables
176
+ ```bash
177
+ # Alpaca API credentials
178
+ export ALPACA_API_KEY="your_api_key"
179
+ export ALPACA_SECRET_KEY="your_secret_key"
180
+
181
+ # UI configuration
182
+ export STREAMLIT_SERVER_PORT=8501
183
+ export DASH_SERVER_PORT=8050
184
+ export JUPYTER_PORT=8888
185
+ export WEBSOCKET_PORT=8765
186
+ ```
187
+
188
+ ### Configuration File
189
+ ```yaml
190
+ # config.yaml
191
+ ui:
192
+ streamlit:
193
+ server_port: 8501
194
+ server_address: "0.0.0.0"
195
+ theme: "light"
196
+
197
+ dash:
198
+ server_port: 8050
199
+ server_address: "0.0.0.0"
200
+ theme: "bootstrap"
201
+
202
+ jupyter:
203
+ port: 8888
204
+ ip: "0.0.0.0"
205
+ token: ""
206
+
207
+ websocket:
208
+ host: "0.0.0.0"
209
+ port: 8765
210
+ max_connections: 100
211
+ ```
212
+
213
+ ## πŸ”§ Customization
214
+
215
+ ### Adding Custom Charts
216
+ ```python
217
+ # In ui/streamlit_app.py
218
+ def create_custom_chart(data):
219
+ fig = go.Figure()
220
+ fig.add_trace(go.Scatter(
221
+ x=data['timestamp'],
222
+ y=data['custom_indicator'],
223
+ name='Custom Indicator'
224
+ ))
225
+ return fig
226
+ ```
227
+
228
+ ### Custom Trading Strategies
229
+ ```python
230
+ # In ui/dash_app.py
231
+ def custom_strategy(data, config):
232
+ # Implement your custom strategy
233
+ signals = []
234
+ for i in range(len(data)):
235
+ if data['sma_20'][i] > data['sma_50'][i]:
236
+ signals.append('BUY')
237
+ else:
238
+ signals.append('SELL')
239
+ return signals
240
+ ```
241
+
242
+ ### WebSocket Custom Messages
243
+ ```python
244
+ # In ui/websocket_server.py
245
+ async def broadcast_custom_message(self, message_type, data):
246
+ message = {
247
+ "type": message_type,
248
+ "timestamp": datetime.now().isoformat(),
249
+ "data": data
250
+ }
251
+ await self.broadcast(message)
252
+ ```
253
+
254
+ ## πŸš€ Deployment
255
+
256
+ ### Docker Deployment
257
+ ```bash
258
+ # Build UI-enabled Docker image
259
+ docker build -t trading-ui .
260
+
261
+ # Run with UI ports exposed
262
+ docker run -p 8501:8501 -p 8050:8050 -p 8888:8888 -p 8765:8765 trading-ui
263
+ ```
264
+
265
+ ### Production Deployment
266
+ ```bash
267
+ # Using Gunicorn for production
268
+ pip install gunicorn
269
+
270
+ # Start Dash app with Gunicorn
271
+ gunicorn -w 4 -b 0.0.0.0:8050 ui.dash_app:app
272
+
273
+ # Start Streamlit with production settings
274
+ streamlit run ui/streamlit_app.py --server.port 8501 --server.address 0.0.0.0
275
+ ```
276
+
277
+ ### Cloud Deployment
278
+ ```bash
279
+ # Deploy to Heroku
280
+ heroku create trading-ui-app
281
+ git push heroku main
282
+
283
+ # Deploy to AWS
284
+ aws ecs create-service --cluster trading-cluster --service-name trading-ui
285
+ ```
286
+
287
+ ## πŸ” Troubleshooting
288
+
289
+ ### Common Issues
290
+
291
+ #### Port Already in Use
292
+ ```bash
293
+ # Find process using port
294
+ lsof -i :8501
295
+
296
+ # Kill process
297
+ kill -9 <PID>
298
+
299
+ # Or use different port
300
+ python ui_launcher.py streamlit --port 8502
301
+ ```
302
+
303
+ #### Missing Dependencies
304
+ ```bash
305
+ # Install missing packages
306
+ pip install streamlit dash plotly ipywidgets
307
+
308
+ # Or reinstall all requirements
309
+ pip install -r requirements.txt
310
+ ```
311
+
312
+ #### Alpaca Connection Issues
313
+ ```bash
314
+ # Check API credentials
315
+ echo $ALPACA_API_KEY
316
+ echo $ALPACA_SECRET_KEY
317
+
318
+ # Test connection
319
+ python -c "from agentic_ai_system.alpaca_broker import AlpacaBroker; print('Connection test')"
320
+ ```
321
+
322
+ ### Debug Mode
323
+ ```bash
324
+ # Enable debug logging
325
+ export LOG_LEVEL=DEBUG
326
+
327
+ # Run with debug output
328
+ python ui_launcher.py streamlit --debug
329
+ ```
330
+
331
+ ## πŸ“š API Reference
332
+
333
+ ### Streamlit Functions
334
+ - `create_streamlit_app()`: Create Streamlit application
335
+ - `TradingUI.run()`: Run the main UI application
336
+ - `load_configuration()`: Load trading configuration
337
+ - `display_system_status()`: Show system status
338
+
339
+ ### Dash Functions
340
+ - `create_dash_app()`: Create Dash application
341
+ - `TradingDashApp.setup_layout()`: Setup dashboard layout
342
+ - `TradingDashApp.setup_callbacks()`: Setup interactive callbacks
343
+
344
+ ### Jupyter Functions
345
+ - `create_jupyter_interface()`: Create Jupyter interface
346
+ - `TradingJupyterUI.display_interface()`: Display interactive widgets
347
+ - `TradingJupyterUI.update_chart()`: Update chart displays
348
+
349
+ ### WebSocket Functions
350
+ - `create_websocket_server()`: Create WebSocket server
351
+ - `TradingWebSocketServer.broadcast()`: Broadcast messages
352
+ - `TradingWebSocketServer.handle_client_message()`: Handle client messages
353
+
354
+ ## 🀝 Contributing
355
+
356
+ ### Adding New UI Features
357
+ 1. Create feature branch: `git checkout -b feature/new-ui-feature`
358
+ 2. Implement feature in appropriate UI module
359
+ 3. Add tests in `tests/ui/` directory
360
+ 4. Update documentation
361
+ 5. Submit pull request
362
+
363
+ ### UI Development Guidelines
364
+ - Follow PEP 8 style guidelines
365
+ - Add type hints for all functions
366
+ - Include docstrings for all classes and methods
367
+ - Write unit tests for new features
368
+ - Update documentation for new features
369
+
370
+ ## πŸ“ž Support
371
+
372
+ For UI-related issues:
373
+ 1. Check the troubleshooting section
374
+ 2. Review the logs in `logs/ui/` directory
375
+ 3. Create an issue on GitHub with detailed error information
376
+ 4. Include system information and error logs
377
+
378
+ ## πŸ”„ Updates
379
+
380
+ ### UI Version History
381
+ - **v1.0.0**: Initial UI implementation with Streamlit, Dash, Jupyter, and WebSocket
382
+ - **v1.1.0**: Added real-time data streaming and advanced charts
383
+ - **v1.2.0**: Enhanced portfolio monitoring and risk management
384
+ - **v1.3.0**: Added custom strategy development tools
385
+
386
+ ### Upcoming Features
387
+ - **v1.4.0**: Machine learning model visualization
388
+ - **v1.5.0**: Advanced backtesting interface
389
+ - **v1.6.0**: Multi-asset portfolio management
390
+ - **v1.7.0**: Social trading features
requirements.txt CHANGED
@@ -1,19 +1,54 @@
1
- pyyaml
2
- pandas
3
- numpy
4
- matplotlib
5
- seaborn
6
- pytest
7
- pytest-cov
8
- python-dateutil
9
- scipy
10
- finrl
11
- stable-baselines3
12
- gymnasium
13
- tensorboard
14
- torch
15
- opencv-python-headless
16
- alpaca-py
17
- python-dotenv
18
- requests
19
- websocket-client
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core dependencies
2
+ numpy>=1.21.0
3
+ pandas>=1.3.0
4
+ scikit-learn>=1.0.0
5
+ matplotlib>=3.5.0
6
+ seaborn>=0.11.0
7
+ yaml>=5.4.0
8
+ requests>=2.25.0
9
+ python-dotenv>=0.19.0
10
+
11
+ # FinRL dependencies
12
+ stable-baselines3>=1.5.0
13
+ gym>=0.21.0
14
+ torch>=1.9.0
15
+
16
+ # Alpaca integration
17
+ alpaca-trade-api>=2.0.0
18
+
19
+ # Testing
20
+ pytest>=6.0.0
21
+ pytest-cov>=2.12.0
22
+
23
+ # UI Dependencies
24
+ streamlit>=1.28.0
25
+ plotly>=5.15.0
26
+ dash>=2.14.0
27
+ dash-bootstrap-components>=1.4.0
28
+ dash-extensions>=1.0.0
29
+ dash-table>=5.0.0
30
+ dash-cytoscape>=0.3.0
31
+ dash-mantine-components>=0.12.0
32
+ dash-iconify>=0.1.0
33
+ dash-uploader>=0.6.0
34
+ dash-daq>=0.5.0
35
+
36
+ # Additional UI enhancements
37
+ rich>=13.0.0
38
+ tqdm>=4.64.0
39
+ ipywidgets>=8.0.0
40
+ voila>=0.4.0
41
+ jupyter-dash>=0.4.0
42
+
43
+ # Real-time updates
44
+ websockets>=10.0
45
+ asyncio-mqtt>=0.11.0
46
+
47
+ # Data visualization
48
+ bokeh>=3.0.0
49
+ altair>=5.0.0
50
+ vega-lite>=5.0.0
51
+
52
+ # Authentication and security
53
+ dash-auth>=2.0.0
54
+ flask-login>=0.6.0
tests/test_ui_integration.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test UI integration for the algorithmic trading system
3
+ """
4
+
5
+ import pytest
6
+ import sys
7
+ import os
8
+ from unittest.mock import patch, MagicMock
9
+
10
+ # Add project root to path
11
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
+
13
+ def test_ui_imports():
14
+ """Test that UI modules can be imported"""
15
+ try:
16
+ from ui import create_streamlit_app, create_dash_app, create_jupyter_interface, TradingWebSocketServer
17
+ assert True
18
+ except ImportError as e:
19
+ pytest.fail(f"Failed to import UI modules: {e}")
20
+
21
+ def test_streamlit_app_creation():
22
+ """Test Streamlit app creation"""
23
+ try:
24
+ from ui.streamlit_app import TradingUI
25
+ ui = TradingUI()
26
+ assert ui is not None
27
+ assert hasattr(ui, 'config')
28
+ assert hasattr(ui, 'data')
29
+ assert hasattr(ui, 'alpaca_broker')
30
+ except Exception as e:
31
+ pytest.fail(f"Failed to create Streamlit UI: {e}")
32
+
33
+ def test_dash_app_creation():
34
+ """Test Dash app creation"""
35
+ try:
36
+ from ui.dash_app import TradingDashApp
37
+ app = TradingDashApp()
38
+ assert app is not None
39
+ assert hasattr(app, 'app')
40
+ assert hasattr(app, 'config')
41
+ except Exception as e:
42
+ pytest.fail(f"Failed to create Dash app: {e}")
43
+
44
+ def test_jupyter_ui_creation():
45
+ """Test Jupyter UI creation"""
46
+ try:
47
+ from ui.jupyter_widgets import TradingJupyterUI
48
+ ui = TradingJupyterUI()
49
+ assert ui is not None
50
+ assert hasattr(ui, 'config')
51
+ assert hasattr(ui, 'data')
52
+ except Exception as e:
53
+ pytest.fail(f"Failed to create Jupyter UI: {e}")
54
+
55
+ def test_websocket_server_creation():
56
+ """Test WebSocket server creation"""
57
+ try:
58
+ from ui.websocket_server import TradingWebSocketServer
59
+ server = TradingWebSocketServer(host="localhost", port=8765)
60
+ assert server is not None
61
+ assert server.host == "localhost"
62
+ assert server.port == 8765
63
+ assert hasattr(server, 'clients')
64
+ except Exception as e:
65
+ pytest.fail(f"Failed to create WebSocket server: {e}")
66
+
67
+ def test_ui_launcher_imports():
68
+ """Test UI launcher imports"""
69
+ try:
70
+ import ui_launcher
71
+ assert hasattr(ui_launcher, 'check_dependencies')
72
+ assert hasattr(ui_launcher, 'launch_streamlit')
73
+ assert hasattr(ui_launcher, 'launch_dash')
74
+ assert hasattr(ui_launcher, 'launch_jupyter')
75
+ assert hasattr(ui_launcher, 'launch_websocket_server')
76
+ except Exception as e:
77
+ pytest.fail(f"Failed to import UI launcher: {e}")
78
+
79
+ @patch('subprocess.run')
80
+ def test_ui_launcher_functions(mock_run):
81
+ """Test UI launcher functions"""
82
+ mock_run.return_value = MagicMock()
83
+
84
+ try:
85
+ import ui_launcher
86
+
87
+ # Test dependency check
88
+ result = ui_launcher.check_dependencies()
89
+ assert isinstance(result, bool)
90
+
91
+ # Test launcher functions (they should not raise exceptions)
92
+ ui_launcher.launch_streamlit()
93
+ ui_launcher.launch_dash()
94
+ ui_launcher.launch_jupyter()
95
+ ui_launcher.launch_websocket_server()
96
+
97
+ except Exception as e:
98
+ pytest.fail(f"Failed to test UI launcher functions: {e}")
99
+
100
+ def test_ui_configuration():
101
+ """Test UI configuration loading"""
102
+ try:
103
+ from agentic_ai_system.main import load_config
104
+ config = load_config()
105
+
106
+ # Check if UI-related config can be added
107
+ config['ui'] = {
108
+ 'streamlit': {
109
+ 'server_port': 8501,
110
+ 'server_address': "0.0.0.0"
111
+ },
112
+ 'dash': {
113
+ 'server_port': 8050,
114
+ 'server_address': "0.0.0.0"
115
+ }
116
+ }
117
+
118
+ assert 'ui' in config
119
+ assert 'streamlit' in config['ui']
120
+ assert 'dash' in config['ui']
121
+
122
+ except Exception as e:
123
+ pytest.fail(f"Failed to test UI configuration: {e}")
124
+
125
+ def test_ui_dependencies():
126
+ """Test that UI dependencies are available"""
127
+ required_packages = [
128
+ 'streamlit',
129
+ 'dash',
130
+ 'plotly',
131
+ 'ipywidgets'
132
+ ]
133
+
134
+ missing_packages = []
135
+ for package in required_packages:
136
+ try:
137
+ __import__(package)
138
+ except ImportError:
139
+ missing_packages.append(package)
140
+
141
+ if missing_packages:
142
+ pytest.skip(f"Missing UI dependencies: {missing_packages}")
143
+ else:
144
+ assert True
145
+
146
+ if __name__ == "__main__":
147
+ pytest.main([__file__])
ui/__init__.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ UI Package for Algorithmic Trading System
3
+
4
+ This package provides multiple UI options:
5
+ - Streamlit: Quick prototyping and data science workflows
6
+ - Dash: Enterprise-grade interactive dashboards
7
+ - Jupyter: Notebook-based interfaces
8
+ - WebSocket: Real-time trading interfaces
9
+ """
10
+
11
+ __version__ = "1.0.0"
12
+ __author__ = "Algorithmic Trading Team"
13
+
14
+ from .streamlit_app import create_streamlit_app
15
+ from .dash_app import create_dash_app
16
+ from .jupyter_widgets import create_jupyter_interface
17
+ from .websocket_server import TradingWebSocketServer
18
+
19
+ __all__ = [
20
+ "create_streamlit_app",
21
+ "create_dash_app",
22
+ "create_jupyter_interface",
23
+ "TradingWebSocketServer"
24
+ ]
ui/dash_app.py ADDED
@@ -0,0 +1,657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Dash UI for Algorithmic Trading System
3
+
4
+ Enterprise-grade interactive dashboard with:
5
+ - Real-time market data visualization
6
+ - Advanced trading analytics
7
+ - Portfolio management
8
+ - Risk monitoring
9
+ - Strategy backtesting
10
+ """
11
+
12
+ import dash
13
+ from dash import dcc, html, Input, Output, State, callback_context
14
+ import dash_bootstrap_components as dbc
15
+ from dash_bootstrap_components import themes
16
+ import plotly.graph_objects as go
17
+ import plotly.express as px
18
+ import pandas as pd
19
+ import numpy as np
20
+ import yaml
21
+ import os
22
+ import sys
23
+ from datetime import datetime, timedelta
24
+ import asyncio
25
+ import threading
26
+ import time
27
+ from typing import Dict, Any, Optional
28
+
29
+ # Add project root to path
30
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
31
+
32
+ from agentic_ai_system.main import load_config
33
+ from agentic_ai_system.data_ingestion import load_data, validate_data, add_technical_indicators
34
+ from agentic_ai_system.finrl_agent import FinRLAgent, FinRLConfig
35
+ from agentic_ai_system.alpaca_broker import AlpacaBroker
36
+ from agentic_ai_system.orchestrator import run_backtest, run_live_trading
37
+
38
+ class TradingDashApp:
39
+ def __init__(self):
40
+ self.app = dash.Dash(
41
+ __name__,
42
+ external_stylesheets=[
43
+ themes.BOOTSTRAP,
44
+ "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
45
+ ],
46
+ suppress_callback_exceptions=True
47
+ )
48
+
49
+ self.config = None
50
+ self.data = None
51
+ self.alpaca_broker = None
52
+ self.finrl_agent = None
53
+
54
+ self.setup_layout()
55
+ self.setup_callbacks()
56
+
57
+ def setup_layout(self):
58
+ """Setup the main application layout"""
59
+ self.app.layout = dbc.Container([
60
+ # Header
61
+ dbc.Row([
62
+ dbc.Col([
63
+ html.H1([
64
+ html.I(className="fas fa-chart-line me-3"),
65
+ "Algorithmic Trading System"
66
+ ], className="text-primary mb-4 text-center")
67
+ ])
68
+ ]),
69
+
70
+ # Navigation tabs
71
+ dbc.Tabs([
72
+ dbc.Tab(self.create_dashboard_tab(), label="Dashboard", tab_id="dashboard"),
73
+ dbc.Tab(self.create_data_tab(), label="Data", tab_id="data"),
74
+ dbc.Tab(self.create_trading_tab(), label="Trading", tab_id="trading"),
75
+ dbc.Tab(self.create_analytics_tab(), label="Analytics", tab_id="analytics"),
76
+ dbc.Tab(self.create_portfolio_tab(), label="Portfolio", tab_id="portfolio"),
77
+ dbc.Tab(self.create_settings_tab(), label="Settings", tab_id="settings")
78
+ ], id="tabs", active_tab="dashboard"),
79
+
80
+ # Store components for data persistence
81
+ dcc.Store(id="config-store"),
82
+ dcc.Store(id="data-store"),
83
+ dcc.Store(id="alpaca-store"),
84
+ dcc.Store(id="finrl-store"),
85
+ dcc.Store(id="trading-status-store"),
86
+
87
+ # Interval for real-time updates
88
+ dcc.Interval(
89
+ id="interval-component",
90
+ interval=5*1000, # 5 seconds
91
+ n_intervals=0
92
+ )
93
+ ], fluid=True)
94
+
95
+ def create_dashboard_tab(self):
96
+ """Create the main dashboard tab"""
97
+ return dbc.Container([
98
+ # System status cards
99
+ dbc.Row([
100
+ dbc.Col(self.create_status_card("Trading Status", "Active", "success"), width=3),
101
+ dbc.Col(self.create_status_card("Portfolio Value", "$100,000", "info"), width=3),
102
+ dbc.Col(self.create_status_card("Daily P&L", "+$1,250", "success"), width=3),
103
+ dbc.Col(self.create_status_card("Risk Level", "Low", "warning"), width=3)
104
+ ], className="mb-4"),
105
+
106
+ # Charts row
107
+ dbc.Row([
108
+ dbc.Col([
109
+ dbc.Card([
110
+ dbc.CardHeader("Price Chart"),
111
+ dbc.CardBody([
112
+ dcc.Graph(id="price-chart", style={"height": "400px"})
113
+ ])
114
+ ])
115
+ ], width=8),
116
+ dbc.Col([
117
+ dbc.Card([
118
+ dbc.CardHeader("Portfolio Allocation"),
119
+ dbc.CardBody([
120
+ dcc.Graph(id="allocation-chart", style={"height": "400px"})
121
+ ])
122
+ ])
123
+ ], width=4)
124
+ ], className="mb-4"),
125
+
126
+ # Trading activity and alerts
127
+ dbc.Row([
128
+ dbc.Col([
129
+ dbc.Card([
130
+ dbc.CardHeader("Recent Trades"),
131
+ dbc.CardBody([
132
+ html.Div(id="trades-table")
133
+ ])
134
+ ])
135
+ ], width=6),
136
+ dbc.Col([
137
+ dbc.Card([
138
+ dbc.CardHeader("System Alerts"),
139
+ dbc.CardBody([
140
+ html.Div(id="alerts-list")
141
+ ])
142
+ ])
143
+ ], width=6)
144
+ ])
145
+ ])
146
+
147
+ def create_data_tab(self):
148
+ """Create the data management tab"""
149
+ return dbc.Container([
150
+ dbc.Row([
151
+ dbc.Col([
152
+ dbc.Card([
153
+ dbc.CardHeader("Data Configuration"),
154
+ dbc.CardBody([
155
+ dbc.Row([
156
+ dbc.Col([
157
+ dbc.Label("Data Source"),
158
+ dbc.Select(
159
+ id="data-source-select",
160
+ options=[
161
+ {"label": "CSV File", "value": "csv"},
162
+ {"label": "Alpaca API", "value": "alpaca"},
163
+ {"label": "Synthetic Data", "value": "synthetic"}
164
+ ],
165
+ value="csv"
166
+ )
167
+ ], width=4),
168
+ dbc.Col([
169
+ dbc.Label("Symbol"),
170
+ dbc.Input(
171
+ id="symbol-input",
172
+ type="text",
173
+ value="AAPL",
174
+ placeholder="Enter symbol"
175
+ )
176
+ ], width=4),
177
+ dbc.Col([
178
+ dbc.Label("Timeframe"),
179
+ dbc.Select(
180
+ id="timeframe-select",
181
+ options=[
182
+ {"label": "1 Minute", "value": "1m"},
183
+ {"label": "5 Minutes", "value": "5m"},
184
+ {"label": "15 Minutes", "value": "15m"},
185
+ {"label": "1 Hour", "value": "1h"},
186
+ {"label": "1 Day", "value": "1d"}
187
+ ],
188
+ value="1m"
189
+ )
190
+ ], width=4)
191
+ ], className="mb-3"),
192
+ dbc.Row([
193
+ dbc.Col([
194
+ dbc.Button("Load Data", id="load-data-btn", color="primary", className="me-2"),
195
+ dbc.Button("Refresh Data", id="refresh-data-btn", color="secondary")
196
+ ])
197
+ ])
198
+ ])
199
+ ])
200
+ ], width=6),
201
+ dbc.Col([
202
+ dbc.Card([
203
+ dbc.CardHeader("Data Statistics"),
204
+ dbc.CardBody([
205
+ html.Div(id="data-stats")
206
+ ])
207
+ ])
208
+ ], width=6)
209
+ ], className="mb-4"),
210
+
211
+ # Data visualization
212
+ dbc.Row([
213
+ dbc.Col([
214
+ dbc.Card([
215
+ dbc.CardHeader([
216
+ html.Span("Market Data Visualization"),
217
+ dbc.ButtonGroup([
218
+ dbc.Button("Candlestick", id="candlestick-btn", size="sm"),
219
+ dbc.Button("Line", id="line-btn", size="sm"),
220
+ dbc.Button("Volume", id="volume-btn", size="sm")
221
+ ], className="float-end")
222
+ ]),
223
+ dbc.CardBody([
224
+ dcc.Graph(id="market-chart", style={"height": "500px"})
225
+ ])
226
+ ])
227
+ ])
228
+ ])
229
+ ])
230
+
231
+ def create_trading_tab(self):
232
+ """Create the trading controls tab"""
233
+ return dbc.Container([
234
+ # Trading configuration
235
+ dbc.Row([
236
+ dbc.Col([
237
+ dbc.Card([
238
+ dbc.CardHeader("Trading Configuration"),
239
+ dbc.CardBody([
240
+ dbc.Row([
241
+ dbc.Col([
242
+ dbc.Label("Capital"),
243
+ dbc.Input(
244
+ id="capital-input",
245
+ type="number",
246
+ value=100000,
247
+ step=1000
248
+ )
249
+ ], width=3),
250
+ dbc.Col([
251
+ dbc.Label("Order Size"),
252
+ dbc.Input(
253
+ id="order-size-input",
254
+ type="number",
255
+ value=10,
256
+ step=1
257
+ )
258
+ ], width=3),
259
+ dbc.Col([
260
+ dbc.Label("Max Position"),
261
+ dbc.Input(
262
+ id="max-position-input",
263
+ type="number",
264
+ value=100,
265
+ step=10
266
+ )
267
+ ], width=3),
268
+ dbc.Col([
269
+ dbc.Label("Max Drawdown"),
270
+ dbc.Input(
271
+ id="max-drawdown-input",
272
+ type="number",
273
+ value=0.05,
274
+ step=0.01,
275
+ min=0,
276
+ max=1
277
+ )
278
+ ], width=3)
279
+ ], className="mb-3"),
280
+ dbc.Row([
281
+ dbc.Col([
282
+ dbc.Button("Start Trading", id="start-trading-btn", color="success", className="me-2"),
283
+ dbc.Button("Stop Trading", id="stop-trading-btn", color="danger", className="me-2"),
284
+ dbc.Button("Emergency Stop", id="emergency-stop-btn", color="warning")
285
+ ])
286
+ ])
287
+ ])
288
+ ])
289
+ ], width=6),
290
+ dbc.Col([
291
+ dbc.Card([
292
+ dbc.CardHeader("Alpaca Connection"),
293
+ dbc.CardBody([
294
+ dbc.Row([
295
+ dbc.Col([
296
+ dbc.Label("API Key"),
297
+ dbc.Input(
298
+ id="alpaca-api-key",
299
+ type="password",
300
+ placeholder="Enter Alpaca API key"
301
+ )
302
+ ], width=6),
303
+ dbc.Col([
304
+ dbc.Label("Secret Key"),
305
+ dbc.Input(
306
+ id="alpaca-secret-key",
307
+ type="password",
308
+ placeholder="Enter Alpaca secret key"
309
+ )
310
+ ], width=6)
311
+ ], className="mb-3"),
312
+ dbc.Row([
313
+ dbc.Col([
314
+ dbc.Button("Connect", id="connect-alpaca-btn", color="primary", className="me-2"),
315
+ dbc.Button("Disconnect", id="disconnect-alpaca-btn", color="secondary")
316
+ ])
317
+ ])
318
+ ])
319
+ ])
320
+ ], width=6)
321
+ ], className="mb-4"),
322
+
323
+ # Trading activity
324
+ dbc.Row([
325
+ dbc.Col([
326
+ dbc.Card([
327
+ dbc.CardHeader("Live Trading Activity"),
328
+ dbc.CardBody([
329
+ html.Div(id="trading-activity")
330
+ ])
331
+ ])
332
+ ])
333
+ ])
334
+ ])
335
+
336
+ def create_analytics_tab(self):
337
+ """Create the analytics tab"""
338
+ return dbc.Container([
339
+ # FinRL training
340
+ dbc.Row([
341
+ dbc.Col([
342
+ dbc.Card([
343
+ dbc.CardHeader("FinRL Model Training"),
344
+ dbc.CardBody([
345
+ dbc.Row([
346
+ dbc.Col([
347
+ dbc.Label("Algorithm"),
348
+ dbc.Select(
349
+ id="finrl-algorithm-select",
350
+ options=[
351
+ {"label": "PPO", "value": "PPO"},
352
+ {"label": "A2C", "value": "A2C"},
353
+ {"label": "DDPG", "value": "DDPG"},
354
+ {"label": "TD3", "value": "TD3"}
355
+ ],
356
+ value="PPO"
357
+ )
358
+ ], width=3),
359
+ dbc.Col([
360
+ dbc.Label("Learning Rate"),
361
+ dbc.Input(
362
+ id="learning-rate-input",
363
+ type="number",
364
+ value=0.0003,
365
+ step=0.0001,
366
+ min=0.0001,
367
+ max=0.01
368
+ )
369
+ ], width=3),
370
+ dbc.Col([
371
+ dbc.Label("Training Steps"),
372
+ dbc.Input(
373
+ id="training-steps-input",
374
+ type="number",
375
+ value=100000,
376
+ step=1000
377
+ )
378
+ ], width=3),
379
+ dbc.Col([
380
+ dbc.Label("Batch Size"),
381
+ dbc.Select(
382
+ id="batch-size-select",
383
+ options=[
384
+ {"label": "32", "value": 32},
385
+ {"label": "64", "value": 64},
386
+ {"label": "128", "value": 128},
387
+ {"label": "256", "value": 256}
388
+ ],
389
+ value=64
390
+ )
391
+ ], width=3)
392
+ ], className="mb-3"),
393
+ dbc.Row([
394
+ dbc.Col([
395
+ dbc.Button("Start Training", id="start-training-btn", color="primary", className="me-2"),
396
+ dbc.Button("Stop Training", id="stop-training-btn", color="danger")
397
+ ])
398
+ ])
399
+ ])
400
+ ])
401
+ ], width=6),
402
+ dbc.Col([
403
+ dbc.Card([
404
+ dbc.CardHeader("Training Progress"),
405
+ dbc.CardBody([
406
+ dbc.Progress(id="training-progress", value=0, className="mb-3"),
407
+ html.Div(id="training-metrics")
408
+ ])
409
+ ])
410
+ ], width=6)
411
+ ], className="mb-4"),
412
+
413
+ # Backtesting
414
+ dbc.Row([
415
+ dbc.Col([
416
+ dbc.Card([
417
+ dbc.CardHeader("Strategy Backtesting"),
418
+ dbc.CardBody([
419
+ dbc.Row([
420
+ dbc.Col([
421
+ dbc.Button("Run Backtest", id="run-backtest-btn", color="primary", className="me-2"),
422
+ dbc.Button("Export Results", id="export-backtest-btn", color="secondary")
423
+ ])
424
+ ]),
425
+ html.Div(id="backtest-results")
426
+ ])
427
+ ])
428
+ ])
429
+ ])
430
+ ])
431
+
432
+ def create_portfolio_tab(self):
433
+ """Create the portfolio management tab"""
434
+ return dbc.Container([
435
+ # Portfolio overview
436
+ dbc.Row([
437
+ dbc.Col([
438
+ dbc.Card([
439
+ dbc.CardHeader("Portfolio Overview"),
440
+ dbc.CardBody([
441
+ dbc.Row([
442
+ dbc.Col([
443
+ html.H4("Total Value", className="text-muted"),
444
+ html.H3(id="total-value", children="$100,000")
445
+ ], width=3),
446
+ dbc.Col([
447
+ html.H4("Cash", className="text-muted"),
448
+ html.H3(id="cash-value", children="$25,000")
449
+ ], width=3),
450
+ dbc.Col([
451
+ html.H4("Invested", className="text-muted"),
452
+ html.H3(id="invested-value", children="$75,000")
453
+ ], width=3),
454
+ dbc.Col([
455
+ html.H4("P&L", className="text-muted"),
456
+ html.H3(id="pnl-value", children="+$1,250", className="text-success")
457
+ ], width=3)
458
+ ])
459
+ ])
460
+ ])
461
+ ])
462
+ ], className="mb-4"),
463
+
464
+ # Positions and allocation
465
+ dbc.Row([
466
+ dbc.Col([
467
+ dbc.Card([
468
+ dbc.CardHeader("Current Positions"),
469
+ dbc.CardBody([
470
+ html.Div(id="positions-table")
471
+ ])
472
+ ])
473
+ ], width=8),
474
+ dbc.Col([
475
+ dbc.Card([
476
+ dbc.CardHeader("Allocation Chart"),
477
+ dbc.CardBody([
478
+ dcc.Graph(id="portfolio-allocation-chart", style={"height": "300px"})
479
+ ])
480
+ ])
481
+ ], width=4)
482
+ ])
483
+ ])
484
+
485
+ def create_settings_tab(self):
486
+ """Create the settings tab"""
487
+ return dbc.Container([
488
+ dbc.Row([
489
+ dbc.Col([
490
+ dbc.Card([
491
+ dbc.CardHeader("System Configuration"),
492
+ dbc.CardBody([
493
+ dbc.Row([
494
+ dbc.Col([
495
+ dbc.Label("Config File"),
496
+ dbc.Input(
497
+ id="config-file-input",
498
+ type="text",
499
+ value="config.yaml",
500
+ placeholder="Enter config file path"
501
+ )
502
+ ], width=6),
503
+ dbc.Col([
504
+ dbc.Label("Log Level"),
505
+ dbc.Select(
506
+ id="log-level-select",
507
+ options=[
508
+ {"label": "DEBUG", "value": "DEBUG"},
509
+ {"label": "INFO", "value": "INFO"},
510
+ {"label": "WARNING", "value": "WARNING"},
511
+ {"label": "ERROR", "value": "ERROR"}
512
+ ],
513
+ value="INFO"
514
+ )
515
+ ], width=6)
516
+ ], className="mb-3"),
517
+ dbc.Row([
518
+ dbc.Col([
519
+ dbc.Button("Load Config", id="load-config-btn", color="primary", className="me-2"),
520
+ dbc.Button("Save Config", id="save-config-btn", color="success")
521
+ ])
522
+ ])
523
+ ])
524
+ ])
525
+ ], width=6),
526
+ dbc.Col([
527
+ dbc.Card([
528
+ dbc.CardHeader("System Status"),
529
+ dbc.CardBody([
530
+ html.Div(id="system-status")
531
+ ])
532
+ ])
533
+ ], width=6)
534
+ ])
535
+ ])
536
+
537
+ def create_status_card(self, title, value, color):
538
+ """Create a status card component"""
539
+ return dbc.Card([
540
+ dbc.CardBody([
541
+ html.H5(title, className="card-title text-muted"),
542
+ html.H3(value, className=f"text-{color}")
543
+ ])
544
+ ])
545
+
546
+ def setup_callbacks(self):
547
+ """Setup all Dash callbacks"""
548
+
549
+ @self.app.callback(
550
+ Output("config-store", "data"),
551
+ Input("load-config-btn", "n_clicks"),
552
+ State("config-file-input", "value"),
553
+ prevent_initial_call=True
554
+ )
555
+ def load_configuration(n_clicks, config_file):
556
+ if n_clicks:
557
+ try:
558
+ config = load_config(config_file)
559
+ return config
560
+ except Exception as e:
561
+ return {"error": str(e)}
562
+ return dash.no_update
563
+
564
+ @self.app.callback(
565
+ Output("data-store", "data"),
566
+ Input("load-data-btn", "n_clicks"),
567
+ State("config-store", "data"),
568
+ prevent_initial_call=True
569
+ )
570
+ def load_market_data(n_clicks, config):
571
+ if n_clicks and config:
572
+ try:
573
+ data = load_data(config)
574
+ if data is not None:
575
+ return data.to_dict('records')
576
+ except Exception as e:
577
+ return {"error": str(e)}
578
+ return dash.no_update
579
+
580
+ @self.app.callback(
581
+ Output("price-chart", "figure"),
582
+ Input("data-store", "data"),
583
+ Input("interval-component", "n_intervals")
584
+ )
585
+ def update_price_chart(data, n_intervals):
586
+ if data and isinstance(data, list):
587
+ df = pd.DataFrame(data)
588
+ if not df.empty:
589
+ fig = go.Figure(data=[go.Candlestick(
590
+ x=df['timestamp'],
591
+ open=df['open'],
592
+ high=df['high'],
593
+ low=df['low'],
594
+ close=df['close']
595
+ )])
596
+ fig.update_layout(
597
+ title="Market Data",
598
+ xaxis_title="Date",
599
+ yaxis_title="Price ($)",
600
+ height=400
601
+ )
602
+ return fig
603
+ return go.Figure()
604
+
605
+ @self.app.callback(
606
+ Output("allocation-chart", "figure"),
607
+ Input("alpaca-store", "data"),
608
+ Input("interval-component", "n_intervals")
609
+ )
610
+ def update_allocation_chart(alpaca_data, n_intervals):
611
+ # Mock portfolio allocation data
612
+ labels = ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'Cash']
613
+ values = [30, 25, 20, 15, 10]
614
+
615
+ fig = go.Figure(data=[go.Pie(labels=labels, values=values)])
616
+ fig.update_layout(
617
+ title="Portfolio Allocation",
618
+ height=400
619
+ )
620
+ return fig
621
+
622
+ @self.app.callback(
623
+ Output("trading-activity", "children"),
624
+ Input("interval-component", "n_intervals")
625
+ )
626
+ def update_trading_activity(n_intervals):
627
+ # Mock trading activity
628
+ trades = [
629
+ {"time": "09:30:15", "symbol": "AAPL", "action": "BUY", "quantity": 10, "price": 150.25},
630
+ {"time": "09:35:22", "symbol": "GOOGL", "action": "SELL", "quantity": 5, "price": 2750.50},
631
+ {"time": "09:40:08", "symbol": "MSFT", "action": "BUY", "quantity": 15, "price": 320.75}
632
+ ]
633
+
634
+ table_rows = []
635
+ for trade in trades:
636
+ color = "success" if trade["action"] == "BUY" else "danger"
637
+ table_rows.append(
638
+ dbc.Row([
639
+ dbc.Col(trade["time"], width=2),
640
+ dbc.Col(trade["symbol"], width=2),
641
+ dbc.Col(trade["action"], width=2, className=f"text-{color}"),
642
+ dbc.Col(str(trade["quantity"]), width=2),
643
+ dbc.Col(f"${trade['price']:.2f}", width=2),
644
+ dbc.Col(f"${trade['quantity'] * trade['price']:.2f}", width=2)
645
+ ], className="mb-2")
646
+ )
647
+
648
+ return table_rows
649
+
650
+ def create_dash_app():
651
+ """Create and return the Dash application"""
652
+ app = TradingDashApp()
653
+ return app.app
654
+
655
+ if __name__ == "__main__":
656
+ app = create_dash_app()
657
+ app.run_server(debug=True, host="0.0.0.0", port=8050)
ui/jupyter_widgets.py ADDED
@@ -0,0 +1,556 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Jupyter Widgets UI for Algorithmic Trading System
3
+
4
+ Interactive notebook interface for:
5
+ - Data exploration and visualization
6
+ - Strategy development and testing
7
+ - Model training and evaluation
8
+ - Real-time trading simulation
9
+ """
10
+
11
+ import ipywidgets as widgets
12
+ from IPython.display import display, HTML, clear_output
13
+ import plotly.graph_objects as go
14
+ import plotly.express as px
15
+ import pandas as pd
16
+ import numpy as np
17
+ import yaml
18
+ import os
19
+ import sys
20
+ from datetime import datetime, timedelta
21
+ from typing import Dict, Any, Optional
22
+ import asyncio
23
+ import threading
24
+ import time
25
+
26
+ # Add project root to path
27
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
28
+
29
+ from agentic_ai_system.main import load_config
30
+ from agentic_ai_system.data_ingestion import load_data, validate_data, add_technical_indicators
31
+ from agentic_ai_system.finrl_agent import FinRLAgent, FinRLConfig
32
+ from agentic_ai_system.alpaca_broker import AlpacaBroker
33
+ from agentic_ai_system.orchestrator import run_backtest, run_live_trading
34
+
35
+ class TradingJupyterUI:
36
+ def __init__(self):
37
+ self.config = None
38
+ self.data = None
39
+ self.alpaca_broker = None
40
+ self.finrl_agent = None
41
+ self.trading_active = False
42
+
43
+ self.setup_widgets()
44
+
45
+ def setup_widgets(self):
46
+ """Setup all interactive widgets"""
47
+
48
+ # Configuration widgets
49
+ self.config_file = widgets.Text(
50
+ value='config.yaml',
51
+ description='Config File:',
52
+ style={'description_width': '120px'}
53
+ )
54
+
55
+ self.load_config_btn = widgets.Button(
56
+ description='Load Configuration',
57
+ button_style='primary',
58
+ icon='cog'
59
+ )
60
+
61
+ self.config_output = widgets.Output()
62
+
63
+ # Data widgets
64
+ self.data_source = widgets.Dropdown(
65
+ options=['csv', 'alpaca', 'synthetic'],
66
+ value='csv',
67
+ description='Data Source:',
68
+ style={'description_width': '120px'}
69
+ )
70
+
71
+ self.symbol_input = widgets.Text(
72
+ value='AAPL',
73
+ description='Symbol:',
74
+ style={'description_width': '120px'}
75
+ )
76
+
77
+ self.timeframe_input = widgets.Dropdown(
78
+ options=['1m', '5m', '15m', '1h', '1d'],
79
+ value='1m',
80
+ description='Timeframe:',
81
+ style={'description_width': '120px'}
82
+ )
83
+
84
+ self.load_data_btn = widgets.Button(
85
+ description='Load Data',
86
+ button_style='success',
87
+ icon='database'
88
+ )
89
+
90
+ self.data_output = widgets.Output()
91
+
92
+ # Alpaca widgets
93
+ self.alpaca_api_key = widgets.Password(
94
+ description='API Key:',
95
+ style={'description_width': '120px'}
96
+ )
97
+
98
+ self.alpaca_secret_key = widgets.Password(
99
+ description='Secret Key:',
100
+ style={'description_width': '120px'}
101
+ )
102
+
103
+ self.connect_alpaca_btn = widgets.Button(
104
+ description='Connect to Alpaca',
105
+ button_style='info',
106
+ icon='link'
107
+ )
108
+
109
+ self.alpaca_output = widgets.Output()
110
+
111
+ # FinRL widgets
112
+ self.finrl_algorithm = widgets.Dropdown(
113
+ options=['PPO', 'A2C', 'DDPG', 'TD3'],
114
+ value='PPO',
115
+ description='Algorithm:',
116
+ style={'description_width': '120px'}
117
+ )
118
+
119
+ self.learning_rate = widgets.FloatSlider(
120
+ value=0.0003,
121
+ min=0.0001,
122
+ max=0.01,
123
+ step=0.0001,
124
+ description='Learning Rate:',
125
+ style={'description_width': '120px'},
126
+ readout_format='.4f'
127
+ )
128
+
129
+ self.training_steps = widgets.IntSlider(
130
+ value=100000,
131
+ min=1000,
132
+ max=1000000,
133
+ step=1000,
134
+ description='Training Steps:',
135
+ style={'description_width': '120px'}
136
+ )
137
+
138
+ self.batch_size = widgets.Dropdown(
139
+ options=[32, 64, 128, 256],
140
+ value=64,
141
+ description='Batch Size:',
142
+ style={'description_width': '120px'}
143
+ )
144
+
145
+ self.start_training_btn = widgets.Button(
146
+ description='Start Training',
147
+ button_style='warning',
148
+ icon='play'
149
+ )
150
+
151
+ self.finrl_output = widgets.Output()
152
+
153
+ # Trading widgets
154
+ self.capital_input = widgets.IntText(
155
+ value=100000,
156
+ description='Capital ($):',
157
+ style={'description_width': '120px'}
158
+ )
159
+
160
+ self.order_size_input = widgets.IntText(
161
+ value=10,
162
+ description='Order Size:',
163
+ style={'description_width': '120px'}
164
+ )
165
+
166
+ self.start_trading_btn = widgets.Button(
167
+ description='Start Trading',
168
+ button_style='danger',
169
+ icon='rocket'
170
+ )
171
+
172
+ self.stop_trading_btn = widgets.Button(
173
+ description='Stop Trading',
174
+ button_style='danger',
175
+ icon='stop'
176
+ )
177
+
178
+ self.trading_output = widgets.Output()
179
+
180
+ # Backtesting widgets
181
+ self.run_backtest_btn = widgets.Button(
182
+ description='Run Backtest',
183
+ button_style='primary',
184
+ icon='chart-line'
185
+ )
186
+
187
+ self.backtest_output = widgets.Output()
188
+
189
+ # Chart widgets
190
+ self.chart_type = widgets.Dropdown(
191
+ options=['Candlestick', 'Line', 'Volume', 'Technical Indicators'],
192
+ value='Candlestick',
193
+ description='Chart Type:',
194
+ style={'description_width': '120px'}
195
+ )
196
+
197
+ self.chart_output = widgets.Output()
198
+
199
+ # Setup callbacks
200
+ self.load_config_btn.on_click(self.on_load_config)
201
+ self.load_data_btn.on_click(self.on_load_data)
202
+ self.connect_alpaca_btn.on_click(self.on_connect_alpaca)
203
+ self.start_training_btn.on_click(self.on_start_training)
204
+ self.start_trading_btn.on_click(self.on_start_trading)
205
+ self.stop_trading_btn.on_click(self.on_stop_trading)
206
+ self.run_backtest_btn.on_click(self.on_run_backtest)
207
+ self.chart_type.observe(self.on_chart_type_change, names='value')
208
+
209
+ def on_load_config(self, b):
210
+ """Handle configuration loading"""
211
+ with self.config_output:
212
+ clear_output()
213
+ try:
214
+ self.config = load_config(self.config_file.value)
215
+ print(f"βœ… Configuration loaded from {self.config_file.value}")
216
+ print(f"Symbol: {self.config['trading']['symbol']}")
217
+ print(f"Capital: ${self.config['trading']['capital']:,}")
218
+ print(f"Timeframe: {self.config['trading']['timeframe']}")
219
+ print(f"Broker: {self.config['execution']['broker_api']}")
220
+ except Exception as e:
221
+ print(f"❌ Error loading configuration: {e}")
222
+
223
+ def on_load_data(self, b):
224
+ """Handle data loading"""
225
+ with self.data_output:
226
+ clear_output()
227
+ try:
228
+ if self.config:
229
+ # Update config with widget values
230
+ self.config['data_source']['type'] = self.data_source.value
231
+ self.config['trading']['symbol'] = self.symbol_input.value
232
+ self.config['trading']['timeframe'] = self.timeframe_input.value
233
+
234
+ print(f"Loading data for {self.symbol_input.value}...")
235
+ self.data = load_data(self.config)
236
+
237
+ if self.data is not None and not self.data.empty:
238
+ print(f"βœ… Loaded {len(self.data)} data points")
239
+ print(f"Date range: {self.data['timestamp'].min()} to {self.data['timestamp'].max()}")
240
+ print(f"Price range: ${self.data['close'].min():.2f} - ${self.data['close'].max():.2f}")
241
+
242
+ # Add technical indicators
243
+ self.data = add_technical_indicators(self.data)
244
+ print(f"βœ… Added technical indicators")
245
+
246
+ # Update chart
247
+ self.update_chart()
248
+ else:
249
+ print("❌ Failed to load data")
250
+ else:
251
+ print("⚠️ Please load configuration first")
252
+ except Exception as e:
253
+ print(f"❌ Error loading data: {e}")
254
+
255
+ def on_connect_alpaca(self, b):
256
+ """Handle Alpaca connection"""
257
+ with self.alpaca_output:
258
+ clear_output()
259
+ try:
260
+ if self.alpaca_api_key.value and self.alpaca_secret_key.value:
261
+ # Update config with API keys
262
+ if self.config:
263
+ self.config['alpaca']['api_key'] = self.alpaca_api_key.value
264
+ self.config['alpaca']['secret_key'] = self.alpaca_secret_key.value
265
+ self.config['execution']['broker_api'] = 'alpaca_paper'
266
+
267
+ print("Connecting to Alpaca...")
268
+ self.alpaca_broker = AlpacaBroker(self.config)
269
+
270
+ account_info = self.alpaca_broker.get_account_info()
271
+ if account_info:
272
+ print("βœ… Connected to Alpaca")
273
+ print(f"Account ID: {account_info['account_id']}")
274
+ print(f"Status: {account_info['status']}")
275
+ print(f"Buying Power: ${account_info['buying_power']:,.2f}")
276
+ print(f"Portfolio Value: ${account_info['portfolio_value']:,.2f}")
277
+ else:
278
+ print("❌ Failed to connect to Alpaca")
279
+ else:
280
+ print("⚠️ Please load configuration first")
281
+ else:
282
+ print("⚠️ Please enter Alpaca API credentials")
283
+ except Exception as e:
284
+ print(f"❌ Error connecting to Alpaca: {e}")
285
+
286
+ def on_start_training(self, b):
287
+ """Handle FinRL training"""
288
+ with self.finrl_output:
289
+ clear_output()
290
+ try:
291
+ if self.data is not None:
292
+ print("Starting FinRL training...")
293
+
294
+ # Create FinRL config
295
+ finrl_config = FinRLConfig(
296
+ algorithm=self.finrl_algorithm.value,
297
+ learning_rate=self.learning_rate.value,
298
+ batch_size=self.batch_size.value,
299
+ buffer_size=1000000,
300
+ learning_starts=100,
301
+ gamma=0.99,
302
+ tau=0.005,
303
+ train_freq=1,
304
+ gradient_steps=1,
305
+ verbose=1,
306
+ tensorboard_log='logs/finrl_tensorboard'
307
+ )
308
+
309
+ # Initialize agent
310
+ self.finrl_agent = FinRLAgent(finrl_config)
311
+
312
+ # Train the agent
313
+ result = self.finrl_agent.train(
314
+ data=self.data,
315
+ config=self.config,
316
+ total_timesteps=self.training_steps.value,
317
+ use_real_broker=False
318
+ )
319
+
320
+ if result['success']:
321
+ print("βœ… Training completed successfully!")
322
+ print(f"Algorithm: {result['algorithm']}")
323
+ print(f"Timesteps: {result['total_timesteps']:,}")
324
+ print(f"Model saved: {result['model_path']}")
325
+ else:
326
+ print("❌ Training failed")
327
+ else:
328
+ print("⚠️ Please load data first")
329
+ except Exception as e:
330
+ print(f"❌ Error during training: {e}")
331
+
332
+ def on_start_trading(self, b):
333
+ """Handle trading start"""
334
+ with self.trading_output:
335
+ clear_output()
336
+ try:
337
+ if self.config and self.alpaca_broker:
338
+ print("Starting live trading...")
339
+ self.trading_active = True
340
+
341
+ # Update config with widget values
342
+ self.config['trading']['capital'] = self.capital_input.value
343
+ self.config['execution']['order_size'] = self.order_size_input.value
344
+
345
+ # Start trading in background thread
346
+ def run_trading():
347
+ try:
348
+ run_live_trading(self.config, self.data)
349
+ except Exception as e:
350
+ print(f"Trading error: {e}")
351
+
352
+ trading_thread = threading.Thread(target=run_trading)
353
+ trading_thread.daemon = True
354
+ trading_thread.start()
355
+
356
+ print("βœ… Live trading started")
357
+ else:
358
+ print("⚠️ Please load configuration and connect to Alpaca first")
359
+ except Exception as e:
360
+ print(f"❌ Error starting trading: {e}")
361
+
362
+ def on_stop_trading(self, b):
363
+ """Handle trading stop"""
364
+ with self.trading_output:
365
+ clear_output()
366
+ self.trading_active = False
367
+ print("βœ… Trading stopped")
368
+
369
+ def on_run_backtest(self, b):
370
+ """Handle backtesting"""
371
+ with self.backtest_output:
372
+ clear_output()
373
+ try:
374
+ if self.config and self.data is not None:
375
+ print("Running backtest...")
376
+
377
+ # Update config with widget values
378
+ self.config['trading']['capital'] = self.capital_input.value
379
+
380
+ result = run_backtest(self.config, self.data)
381
+
382
+ if result['success']:
383
+ print("βœ… Backtest completed")
384
+ print(f"Total Return: {result['total_return']:.2%}")
385
+ print(f"Sharpe Ratio: {result['sharpe_ratio']:.2f}")
386
+ print(f"Max Drawdown: {result['max_drawdown']:.2%}")
387
+ print(f"Total Trades: {result['total_trades']}")
388
+ else:
389
+ print("❌ Backtest failed")
390
+ else:
391
+ print("⚠️ Please load configuration and data first")
392
+ except Exception as e:
393
+ print(f"❌ Error during backtest: {e}")
394
+
395
+ def on_chart_type_change(self, change):
396
+ """Handle chart type change"""
397
+ if self.data is not None:
398
+ self.update_chart()
399
+
400
+ def update_chart(self):
401
+ """Update the chart display"""
402
+ with self.chart_output:
403
+ clear_output()
404
+
405
+ if self.data is None:
406
+ return
407
+
408
+ if self.chart_type.value == "Candlestick":
409
+ fig = go.Figure(data=[go.Candlestick(
410
+ x=self.data['timestamp'],
411
+ open=self.data['open'],
412
+ high=self.data['high'],
413
+ low=self.data['low'],
414
+ close=self.data['close']
415
+ )])
416
+ fig.update_layout(
417
+ title=f"{self.config['trading']['symbol']} Candlestick Chart",
418
+ xaxis_title="Date",
419
+ yaxis_title="Price ($)",
420
+ height=500
421
+ )
422
+ display(fig)
423
+
424
+ elif self.chart_type.value == "Line":
425
+ fig = px.line(self.data, x='timestamp', y='close',
426
+ title=f"{self.config['trading']['symbol']} Price Chart")
427
+ fig.update_layout(height=500)
428
+ display(fig)
429
+
430
+ elif self.chart_type.value == "Volume":
431
+ fig = go.Figure()
432
+ fig.add_trace(go.Bar(
433
+ x=self.data['timestamp'],
434
+ y=self.data['volume'],
435
+ name='Volume'
436
+ ))
437
+ fig.update_layout(
438
+ title=f"{self.config['trading']['symbol']} Volume Chart",
439
+ xaxis_title="Date",
440
+ yaxis_title="Volume",
441
+ height=500
442
+ )
443
+ display(fig)
444
+
445
+ elif self.chart_type.value == "Technical Indicators":
446
+ fig = go.Figure()
447
+
448
+ # Add price
449
+ fig.add_trace(go.Scatter(
450
+ x=self.data['timestamp'],
451
+ y=self.data['close'],
452
+ name='Close Price',
453
+ line=dict(color='blue')
454
+ ))
455
+
456
+ # Add moving averages if available
457
+ if 'sma_20' in self.data.columns:
458
+ fig.add_trace(go.Scatter(
459
+ x=self.data['timestamp'],
460
+ y=self.data['sma_20'],
461
+ name='SMA 20',
462
+ line=dict(color='orange')
463
+ ))
464
+
465
+ if 'sma_50' in self.data.columns:
466
+ fig.add_trace(go.Scatter(
467
+ x=self.data['timestamp'],
468
+ y=self.data['sma_50'],
469
+ name='SMA 50',
470
+ line=dict(color='red')
471
+ ))
472
+
473
+ fig.update_layout(
474
+ title=f"{self.config['trading']['symbol']} Technical Indicators",
475
+ xaxis_title="Date",
476
+ yaxis_title="Price ($)",
477
+ height=500
478
+ )
479
+ display(fig)
480
+
481
+ def display_interface(self):
482
+ """Display the complete Jupyter interface"""
483
+
484
+ # Header
485
+ display(HTML("""
486
+ <div style="text-align: center; margin-bottom: 20px;">
487
+ <h1>πŸ€– Algorithmic Trading System</h1>
488
+ <p>Interactive Jupyter Interface for Trading Analysis</p>
489
+ </div>
490
+ """))
491
+
492
+ # Configuration section
493
+ display(HTML("<h2>βš™οΈ Configuration</h2>"))
494
+ config_widgets = widgets.VBox([
495
+ widgets.HBox([self.config_file, self.load_config_btn]),
496
+ self.config_output
497
+ ])
498
+ display(config_widgets)
499
+
500
+ # Data section
501
+ display(HTML("<h2>πŸ“₯ Data Management</h2>"))
502
+ data_widgets = widgets.VBox([
503
+ widgets.HBox([self.data_source, self.symbol_input, self.timeframe_input]),
504
+ widgets.HBox([self.load_data_btn]),
505
+ self.data_output
506
+ ])
507
+ display(data_widgets)
508
+
509
+ # Alpaca section
510
+ display(HTML("<h2>🏦 Alpaca Integration</h2>"))
511
+ alpaca_widgets = widgets.VBox([
512
+ widgets.HBox([self.alpaca_api_key, self.alpaca_secret_key]),
513
+ widgets.HBox([self.connect_alpaca_btn]),
514
+ self.alpaca_output
515
+ ])
516
+ display(alpaca_widgets)
517
+
518
+ # FinRL section
519
+ display(HTML("<h2>🧠 FinRL Training</h2>"))
520
+ finrl_widgets = widgets.VBox([
521
+ widgets.HBox([self.finrl_algorithm, self.learning_rate]),
522
+ widgets.HBox([self.training_steps, self.batch_size]),
523
+ widgets.HBox([self.start_training_btn]),
524
+ self.finrl_output
525
+ ])
526
+ display(finrl_widgets)
527
+
528
+ # Trading section
529
+ display(HTML("<h2>🎯 Trading Controls</h2>"))
530
+ trading_widgets = widgets.VBox([
531
+ widgets.HBox([self.capital_input, self.order_size_input]),
532
+ widgets.HBox([self.start_trading_btn, self.stop_trading_btn]),
533
+ self.trading_output
534
+ ])
535
+ display(trading_widgets)
536
+
537
+ # Backtesting section
538
+ display(HTML("<h2>πŸ“Š Backtesting</h2>"))
539
+ backtest_widgets = widgets.VBox([
540
+ widgets.HBox([self.run_backtest_btn]),
541
+ self.backtest_output
542
+ ])
543
+ display(backtest_widgets)
544
+
545
+ # Chart section
546
+ display(HTML("<h2>πŸ“ˆ Data Visualization</h2>"))
547
+ chart_widgets = widgets.VBox([
548
+ widgets.HBox([self.chart_type]),
549
+ self.chart_output
550
+ ])
551
+ display(chart_widgets)
552
+
553
+ def create_jupyter_interface():
554
+ """Create and return the Jupyter interface"""
555
+ ui = TradingJupyterUI()
556
+ return ui
ui/streamlit_app.py ADDED
@@ -0,0 +1,679 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Streamlit UI for Algorithmic Trading System
3
+
4
+ A comprehensive web interface for:
5
+ - Real-time market data visualization
6
+ - Trading strategy configuration
7
+ - FinRL model training and evaluation
8
+ - Portfolio management
9
+ - Risk monitoring
10
+ """
11
+
12
+ import streamlit as st
13
+ import plotly.graph_objects as go
14
+ import plotly.express as px
15
+ import pandas as pd
16
+ import numpy as np
17
+ import yaml
18
+ import os
19
+ import sys
20
+ from datetime import datetime, timedelta
21
+ from typing import Dict, Any, Optional
22
+ import asyncio
23
+ import threading
24
+ import time
25
+
26
+ # Add project root to path
27
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
28
+
29
+ from agentic_ai_system.main import load_config
30
+ from agentic_ai_system.data_ingestion import load_data, validate_data, add_technical_indicators
31
+ from agentic_ai_system.finrl_agent import FinRLAgent, FinRLConfig
32
+ from agentic_ai_system.alpaca_broker import AlpacaBroker
33
+ from agentic_ai_system.orchestrator import run_backtest, run_live_trading
34
+
35
+ # Page configuration
36
+ st.set_page_config(
37
+ page_title="Algorithmic Trading System",
38
+ page_icon="πŸ“ˆ",
39
+ layout="wide",
40
+ initial_sidebar_state="expanded"
41
+ )
42
+
43
+ # Custom CSS for better styling
44
+ st.markdown("""
45
+ <style>
46
+ .main-header {
47
+ font-size: 2.5rem;
48
+ font-weight: bold;
49
+ color: #1f77b4;
50
+ text-align: center;
51
+ margin-bottom: 2rem;
52
+ }
53
+ .metric-card {
54
+ background-color: #f0f2f6;
55
+ padding: 1rem;
56
+ border-radius: 0.5rem;
57
+ border-left: 4px solid #1f77b4;
58
+ }
59
+ .success-metric {
60
+ border-left-color: #28a745;
61
+ }
62
+ .warning-metric {
63
+ border-left-color: #ffc107;
64
+ }
65
+ .danger-metric {
66
+ border-left-color: #dc3545;
67
+ }
68
+ .sidebar .sidebar-content {
69
+ background-color: #f8f9fa;
70
+ }
71
+ </style>
72
+ """, unsafe_allow_html=True)
73
+
74
+ class TradingUI:
75
+ def __init__(self):
76
+ self.config = None
77
+ self.data = None
78
+ self.alpaca_broker = None
79
+ self.finrl_agent = None
80
+ self.session_state = st.session_state
81
+
82
+ # Initialize session state
83
+ if 'trading_active' not in self.session_state:
84
+ self.session_state.trading_active = False
85
+ if 'current_portfolio' not in self.session_state:
86
+ self.session_state.current_portfolio = {}
87
+ if 'trading_history' not in self.session_state:
88
+ self.session_state.trading_history = []
89
+
90
+ def load_configuration(self):
91
+ """Load and display configuration"""
92
+ st.sidebar.header("βš™οΈ Configuration")
93
+
94
+ # Config file selector
95
+ config_files = [f for f in os.listdir('.') if f.endswith('.yaml') or f.endswith('.yml')]
96
+ selected_config = st.sidebar.selectbox(
97
+ "Select Configuration File",
98
+ config_files,
99
+ index=0 if 'config.yaml' in config_files else 0
100
+ )
101
+
102
+ if st.sidebar.button("Load Configuration"):
103
+ try:
104
+ self.config = load_config(selected_config)
105
+ st.sidebar.success(f"βœ… Configuration loaded: {selected_config}")
106
+ return True
107
+ except Exception as e:
108
+ st.sidebar.error(f"❌ Error loading config: {e}")
109
+ return False
110
+
111
+ return False
112
+
113
+ def display_system_status(self):
114
+ """Display system status and metrics"""
115
+ st.header("πŸ“Š System Status")
116
+
117
+ col1, col2, col3, col4 = st.columns(4)
118
+
119
+ with col1:
120
+ st.metric(
121
+ label="Trading Status",
122
+ value="🟒 Active" if self.session_state.trading_active else "πŸ”΄ Inactive",
123
+ delta="Running" if self.session_state.trading_active else "Stopped"
124
+ )
125
+
126
+ with col2:
127
+ if self.config:
128
+ st.metric(
129
+ label="Capital",
130
+ value=f"${self.config['trading']['capital']:,}",
131
+ delta="Available"
132
+ )
133
+ else:
134
+ st.metric(label="Capital", value="Not Loaded")
135
+
136
+ with col3:
137
+ if self.alpaca_broker:
138
+ try:
139
+ account_info = self.alpaca_broker.get_account_info()
140
+ if account_info:
141
+ st.metric(
142
+ label="Portfolio Value",
143
+ value=f"${float(account_info['portfolio_value']):,.2f}",
144
+ delta=f"{float(account_info['equity']) - float(account_info['portfolio_value']):,.2f}"
145
+ )
146
+ except:
147
+ st.metric(label="Portfolio Value", value="Not Connected")
148
+ else:
149
+ st.metric(label="Portfolio Value", value="Not Connected")
150
+
151
+ with col4:
152
+ if self.data is not None:
153
+ st.metric(
154
+ label="Data Points",
155
+ value=f"{len(self.data):,}",
156
+ delta=f"Latest: {self.data['timestamp'].max().strftime('%Y-%m-%d')}"
157
+ )
158
+ else:
159
+ st.metric(label="Data Points", value="Not Loaded")
160
+
161
+ def data_ingestion_panel(self):
162
+ """Data ingestion and visualization panel"""
163
+ st.header("πŸ“₯ Data Ingestion")
164
+
165
+ col1, col2 = st.columns([2, 1])
166
+
167
+ with col1:
168
+ if self.config:
169
+ if st.button("Load Market Data"):
170
+ with st.spinner("Loading data..."):
171
+ try:
172
+ self.data = load_data(self.config)
173
+ if self.data is not None and not self.data.empty:
174
+ st.success(f"βœ… Loaded {len(self.data)} data points")
175
+
176
+ # Add technical indicators
177
+ self.data = add_technical_indicators(self.data)
178
+ st.info(f"βœ… Added technical indicators")
179
+ else:
180
+ st.error("❌ Failed to load data")
181
+ except Exception as e:
182
+ st.error(f"❌ Error loading data: {e}")
183
+
184
+ with col2:
185
+ if self.data is not None:
186
+ st.subheader("Data Summary")
187
+ st.write(f"**Symbol:** {self.config['trading']['symbol']}")
188
+ st.write(f"**Timeframe:** {self.config['trading']['timeframe']}")
189
+ st.write(f"**Date Range:** {self.data['timestamp'].min().strftime('%Y-%m-%d')} to {self.data['timestamp'].max().strftime('%Y-%m-%d')}")
190
+ st.write(f"**Price Range:** ${self.data['close'].min():.2f} - ${self.data['close'].max():.2f}")
191
+
192
+ # Data visualization
193
+ if self.data is not None:
194
+ st.subheader("πŸ“ˆ Market Data Visualization")
195
+
196
+ # Chart type selector
197
+ chart_type = st.selectbox(
198
+ "Chart Type",
199
+ ["Candlestick", "Line", "OHLC", "Volume"]
200
+ )
201
+
202
+ if chart_type == "Candlestick":
203
+ fig = go.Figure(data=[go.Candlestick(
204
+ x=self.data['timestamp'],
205
+ open=self.data['open'],
206
+ high=self.data['high'],
207
+ low=self.data['low'],
208
+ close=self.data['close']
209
+ )])
210
+ fig.update_layout(
211
+ title=f"{self.config['trading']['symbol']} Candlestick Chart",
212
+ xaxis_title="Date",
213
+ yaxis_title="Price ($)",
214
+ height=500
215
+ )
216
+ st.plotly_chart(fig, use_container_width=True)
217
+
218
+ elif chart_type == "Line":
219
+ fig = px.line(self.data, x='timestamp', y='close',
220
+ title=f"{self.config['trading']['symbol']} Price Chart")
221
+ fig.update_layout(height=500)
222
+ st.plotly_chart(fig, use_container_width=True)
223
+
224
+ elif chart_type == "Volume":
225
+ fig = go.Figure()
226
+ fig.add_trace(go.Bar(
227
+ x=self.data['timestamp'],
228
+ y=self.data['volume'],
229
+ name='Volume'
230
+ ))
231
+ fig.update_layout(
232
+ title=f"{self.config['trading']['symbol']} Volume Chart",
233
+ xaxis_title="Date",
234
+ yaxis_title="Volume",
235
+ height=500
236
+ )
237
+ st.plotly_chart(fig, use_container_width=True)
238
+
239
+ def alpaca_integration_panel(self):
240
+ """Alpaca broker integration panel"""
241
+ st.header("🏦 Alpaca Integration")
242
+
243
+ col1, col2 = st.columns([1, 1])
244
+
245
+ with col1:
246
+ if st.button("Connect to Alpaca"):
247
+ if self.config and self.config['execution']['broker_api'] in ['alpaca_paper', 'alpaca_live']:
248
+ with st.spinner("Connecting to Alpaca..."):
249
+ try:
250
+ self.alpaca_broker = AlpacaBroker(self.config)
251
+ account_info = self.alpaca_broker.get_account_info()
252
+ if account_info:
253
+ st.success("βœ… Connected to Alpaca")
254
+ self.session_state.alpaca_connected = True
255
+ else:
256
+ st.error("❌ Failed to connect to Alpaca")
257
+ except Exception as e:
258
+ st.error(f"❌ Connection error: {e}")
259
+ else:
260
+ st.warning("⚠️ Alpaca not configured in settings")
261
+
262
+ with col2:
263
+ if st.button("Disconnect from Alpaca"):
264
+ self.alpaca_broker = None
265
+ self.session_state.alpaca_connected = False
266
+ st.success("βœ… Disconnected from Alpaca")
267
+
268
+ # Account information display
269
+ if self.alpaca_broker:
270
+ st.subheader("Account Information")
271
+
272
+ try:
273
+ account_info = self.alpaca_broker.get_account_info()
274
+ if account_info:
275
+ col1, col2, col3 = st.columns(3)
276
+
277
+ with col1:
278
+ st.metric(
279
+ label="Buying Power",
280
+ value=f"${float(account_info['buying_power']):,.2f}"
281
+ )
282
+
283
+ with col2:
284
+ st.metric(
285
+ label="Portfolio Value",
286
+ value=f"${float(account_info['portfolio_value']):,.2f}"
287
+ )
288
+
289
+ with col3:
290
+ st.metric(
291
+ label="Equity",
292
+ value=f"${float(account_info['equity']):,.2f}"
293
+ )
294
+
295
+ # Market hours
296
+ market_hours = self.alpaca_broker.get_market_hours()
297
+ if market_hours:
298
+ status_color = "🟒" if market_hours['is_open'] else "πŸ”΄"
299
+ st.info(f"{status_color} Market Status: {'OPEN' if market_hours['is_open'] else 'CLOSED'}")
300
+
301
+ if market_hours['next_open']:
302
+ st.write(f"Next Open: {market_hours['next_open']}")
303
+ if market_hours['next_close']:
304
+ st.write(f"Next Close: {market_hours['next_close']}")
305
+
306
+ # Current positions
307
+ positions = self.alpaca_broker.get_positions()
308
+ if positions:
309
+ st.subheader("Current Positions")
310
+ positions_df = pd.DataFrame(positions)
311
+ st.dataframe(positions_df)
312
+ else:
313
+ st.info("No current positions")
314
+
315
+ except Exception as e:
316
+ st.error(f"Error fetching account info: {e}")
317
+
318
+ def finrl_training_panel(self):
319
+ """FinRL model training panel"""
320
+ st.header("🧠 FinRL Model Training")
321
+
322
+ if not self.data is not None:
323
+ st.warning("⚠️ Please load market data first")
324
+ return
325
+
326
+ col1, col2 = st.columns([2, 1])
327
+
328
+ with col1:
329
+ st.subheader("Training Configuration")
330
+
331
+ # Training parameters
332
+ algorithm = st.selectbox(
333
+ "Algorithm",
334
+ ["PPO", "A2C", "DDPG", "TD3"],
335
+ index=0
336
+ )
337
+
338
+ learning_rate = st.slider(
339
+ "Learning Rate",
340
+ min_value=0.0001,
341
+ max_value=0.01,
342
+ value=0.0003,
343
+ step=0.0001,
344
+ format="%.4f"
345
+ )
346
+
347
+ total_timesteps = st.slider(
348
+ "Total Timesteps",
349
+ min_value=1000,
350
+ max_value=1000000,
351
+ value=100000,
352
+ step=1000
353
+ )
354
+
355
+ batch_size = st.selectbox(
356
+ "Batch Size",
357
+ [32, 64, 128, 256],
358
+ index=1
359
+ )
360
+
361
+ with col2:
362
+ st.subheader("Training Controls")
363
+
364
+ if st.button("Start Training", type="primary"):
365
+ if self.data is not None:
366
+ with st.spinner("Training FinRL model..."):
367
+ try:
368
+ # Create FinRL config
369
+ finrl_config = FinRLConfig(
370
+ algorithm=algorithm,
371
+ learning_rate=learning_rate,
372
+ batch_size=batch_size,
373
+ buffer_size=1000000,
374
+ learning_starts=100,
375
+ gamma=0.99,
376
+ tau=0.005,
377
+ train_freq=1,
378
+ gradient_steps=1,
379
+ verbose=1,
380
+ tensorboard_log='logs/finrl_tensorboard'
381
+ )
382
+
383
+ # Initialize agent
384
+ self.finrl_agent = FinRLAgent(finrl_config)
385
+
386
+ # Train the agent
387
+ result = self.finrl_agent.train(
388
+ data=self.data,
389
+ config=self.config,
390
+ total_timesteps=total_timesteps,
391
+ use_real_broker=False
392
+ )
393
+
394
+ if result['success']:
395
+ st.success("βœ… Training completed successfully!")
396
+ st.write(f"Model saved: {result['model_path']}")
397
+ self.session_state.model_trained = True
398
+ else:
399
+ st.error("❌ Training failed")
400
+
401
+ except Exception as e:
402
+ st.error(f"❌ Training error: {e}")
403
+
404
+ # Training progress and metrics
405
+ if hasattr(self.session_state, 'model_trained') and self.session_state.model_trained:
406
+ st.subheader("Model Performance")
407
+
408
+ if st.button("Evaluate Model"):
409
+ if self.finrl_agent:
410
+ with st.spinner("Evaluating model..."):
411
+ try:
412
+ # Use last 100 data points for evaluation
413
+ eval_data = self.data.tail(100)
414
+ prediction_result = self.finrl_agent.predict(
415
+ data=eval_data,
416
+ config=self.config,
417
+ use_real_broker=False
418
+ )
419
+
420
+ if prediction_result['success']:
421
+ col1, col2, col3 = st.columns(3)
422
+
423
+ with col1:
424
+ st.metric(
425
+ label="Initial Value",
426
+ value=f"${prediction_result['initial_value']:,.2f}"
427
+ )
428
+
429
+ with col2:
430
+ st.metric(
431
+ label="Final Value",
432
+ value=f"${prediction_result['final_value']:,.2f}"
433
+ )
434
+
435
+ with col3:
436
+ return_pct = prediction_result['total_return'] * 100
437
+ st.metric(
438
+ label="Total Return",
439
+ value=f"{return_pct:.2f}%",
440
+ delta=f"{return_pct:.2f}%"
441
+ )
442
+
443
+ st.write(f"Total Trades: {prediction_result['total_trades']}")
444
+ else:
445
+ st.error("❌ Model evaluation failed")
446
+
447
+ except Exception as e:
448
+ st.error(f"❌ Evaluation error: {e}")
449
+
450
+ def trading_controls_panel(self):
451
+ """Trading controls and execution panel"""
452
+ st.header("🎯 Trading Controls")
453
+
454
+ col1, col2 = st.columns([1, 1])
455
+
456
+ with col1:
457
+ st.subheader("Backtesting")
458
+
459
+ if st.button("Run Backtest"):
460
+ if self.data is not None and self.config:
461
+ with st.spinner("Running backtest..."):
462
+ try:
463
+ result = run_backtest(self.config, self.data)
464
+ if result['success']:
465
+ st.success("βœ… Backtest completed")
466
+
467
+ # Display backtest results
468
+ col1, col2, col3 = st.columns(3)
469
+
470
+ with col1:
471
+ st.metric(
472
+ label="Total Return",
473
+ value=f"{result['total_return']:.2%}"
474
+ )
475
+
476
+ with col2:
477
+ st.metric(
478
+ label="Sharpe Ratio",
479
+ value=f"{result['sharpe_ratio']:.2f}"
480
+ )
481
+
482
+ with col3:
483
+ st.metric(
484
+ label="Max Drawdown",
485
+ value=f"{result['max_drawdown']:.2%}"
486
+ )
487
+
488
+ # Store results in session state
489
+ self.session_state.backtest_results = result
490
+ else:
491
+ st.error("❌ Backtest failed")
492
+
493
+ except Exception as e:
494
+ st.error(f"❌ Backtest error: {e}")
495
+
496
+ with col2:
497
+ st.subheader("Live Trading")
498
+
499
+ if st.button("Start Live Trading", type="primary"):
500
+ if self.config and self.alpaca_broker:
501
+ self.session_state.trading_active = True
502
+ st.success("βœ… Live trading started")
503
+
504
+ # Start trading in background thread
505
+ def run_trading():
506
+ try:
507
+ run_live_trading(self.config, self.data)
508
+ except Exception as e:
509
+ st.error(f"Trading error: {e}")
510
+
511
+ trading_thread = threading.Thread(target=run_trading)
512
+ trading_thread.daemon = True
513
+ trading_thread.start()
514
+ else:
515
+ st.warning("⚠️ Please configure Alpaca connection first")
516
+
517
+ if st.button("Stop Live Trading"):
518
+ self.session_state.trading_active = False
519
+ st.success("βœ… Live trading stopped")
520
+
521
+ def portfolio_monitoring_panel(self):
522
+ """Portfolio monitoring and analytics panel"""
523
+ st.header("πŸ“Š Portfolio Monitoring")
524
+
525
+ if not self.alpaca_broker:
526
+ st.warning("⚠️ Connect to Alpaca to view portfolio")
527
+ return
528
+
529
+ try:
530
+ # Portfolio overview
531
+ account_info = self.alpaca_broker.get_account_info()
532
+ if account_info:
533
+ col1, col2, col3, col4 = st.columns(4)
534
+
535
+ with col1:
536
+ st.metric(
537
+ label="Total Value",
538
+ value=f"${float(account_info['portfolio_value']):,.2f}"
539
+ )
540
+
541
+ with col2:
542
+ st.metric(
543
+ label="Cash",
544
+ value=f"${float(account_info['cash']):,.2f}"
545
+ )
546
+
547
+ with col3:
548
+ st.metric(
549
+ label="Buying Power",
550
+ value=f"${float(account_info['buying_power']):,.2f}"
551
+ )
552
+
553
+ with col4:
554
+ equity = float(account_info['equity'])
555
+ portfolio_value = float(account_info['portfolio_value'])
556
+ pnl = equity - portfolio_value
557
+ st.metric(
558
+ label="P&L",
559
+ value=f"${pnl:,.2f}",
560
+ delta=f"{pnl:,.2f}"
561
+ )
562
+
563
+ # Positions table
564
+ positions = self.alpaca_broker.get_positions()
565
+ if positions:
566
+ st.subheader("Current Positions")
567
+
568
+ positions_df = pd.DataFrame(positions)
569
+ if not positions_df.empty:
570
+ # Calculate additional metrics
571
+ positions_df['market_value'] = positions_df['quantity'].astype(float) * positions_df['current_price'].astype(float)
572
+ positions_df['unrealized_pl'] = positions_df['unrealized_pl'].astype(float)
573
+ positions_df['unrealized_plpc'] = positions_df['unrealized_plpc'].astype(float)
574
+
575
+ # Display positions
576
+ st.dataframe(
577
+ positions_df[['symbol', 'quantity', 'current_price', 'market_value', 'unrealized_pl', 'unrealized_plpc']],
578
+ use_container_width=True
579
+ )
580
+
581
+ # Position chart
582
+ fig = px.pie(
583
+ positions_df,
584
+ values='market_value',
585
+ names='symbol',
586
+ title="Portfolio Allocation"
587
+ )
588
+ st.plotly_chart(fig, use_container_width=True)
589
+ else:
590
+ st.info("No positions found")
591
+ else:
592
+ st.info("No current positions")
593
+
594
+ except Exception as e:
595
+ st.error(f"Error fetching portfolio data: {e}")
596
+
597
+ def run(self):
598
+ """Main UI application"""
599
+ # Header
600
+ st.markdown('<h1 class="main-header">πŸ€– Algorithmic Trading System</h1>', unsafe_allow_html=True)
601
+
602
+ # Load configuration
603
+ if self.load_configuration():
604
+ self.config = load_config('config.yaml')
605
+
606
+ # Sidebar navigation
607
+ st.sidebar.title("Navigation")
608
+ page = st.sidebar.selectbox(
609
+ "Select Page",
610
+ ["Dashboard", "Data Ingestion", "Alpaca Integration", "FinRL Training", "Trading Controls", "Portfolio Monitoring"]
611
+ )
612
+
613
+ # Display system status
614
+ self.display_system_status()
615
+
616
+ # Page routing
617
+ if page == "Dashboard":
618
+ st.header("πŸ“Š Dashboard")
619
+
620
+ if self.config:
621
+ st.subheader("System Configuration")
622
+ config_col1, config_col2 = st.columns(2)
623
+
624
+ with config_col1:
625
+ st.write(f"**Symbol:** {self.config['trading']['symbol']}")
626
+ st.write(f"**Capital:** ${self.config['trading']['capital']:,}")
627
+ st.write(f"**Timeframe:** {self.config['trading']['timeframe']}")
628
+
629
+ with config_col2:
630
+ st.write(f"**Broker:** {self.config['execution']['broker_api']}")
631
+ st.write(f"**FinRL Algorithm:** {self.config['finrl']['algorithm']}")
632
+ st.write(f"**Risk Max Drawdown:** {self.config['risk']['max_drawdown']:.1%}")
633
+
634
+ # Quick actions
635
+ st.subheader("Quick Actions")
636
+ col1, col2, col3 = st.columns(3)
637
+
638
+ with col1:
639
+ if st.button("Load Data", type="primary"):
640
+ if self.config:
641
+ with st.spinner("Loading data..."):
642
+ self.data = load_data(self.config)
643
+ if self.data is not None:
644
+ st.success("βœ… Data loaded successfully")
645
+
646
+ with col2:
647
+ if st.button("Connect Alpaca"):
648
+ if self.config and self.config['execution']['broker_api'] in ['alpaca_paper', 'alpaca_live']:
649
+ with st.spinner("Connecting..."):
650
+ self.alpaca_broker = AlpacaBroker(self.config)
651
+ st.success("βœ… Connected to Alpaca")
652
+
653
+ with col3:
654
+ if st.button("Start Training"):
655
+ if self.data is not None:
656
+ st.info("Navigate to FinRL Training page to configure and start training")
657
+
658
+ elif page == "Data Ingestion":
659
+ self.data_ingestion_panel()
660
+
661
+ elif page == "Alpaca Integration":
662
+ self.alpaca_integration_panel()
663
+
664
+ elif page == "FinRL Training":
665
+ self.finrl_training_panel()
666
+
667
+ elif page == "Trading Controls":
668
+ self.trading_controls_panel()
669
+
670
+ elif page == "Portfolio Monitoring":
671
+ self.portfolio_monitoring_panel()
672
+
673
+ def main():
674
+ """Main application entry point"""
675
+ ui = TradingUI()
676
+ ui.run()
677
+
678
+ if __name__ == "__main__":
679
+ main()
ui/websocket_server.py ADDED
@@ -0,0 +1,461 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ WebSocket Server for Real-time Trading Data
3
+
4
+ Provides real-time updates for:
5
+ - Market data streaming
6
+ - Trading signals
7
+ - Portfolio updates
8
+ - System alerts
9
+ """
10
+
11
+ import asyncio
12
+ import websockets
13
+ import json
14
+ import logging
15
+ import threading
16
+ import time
17
+ from datetime import datetime, timedelta
18
+ from typing import Dict, Any, List, Optional
19
+ import pandas as pd
20
+ import os
21
+ import sys
22
+
23
+ # Add project root to path
24
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
25
+
26
+ from agentic_ai_system.main import load_config
27
+ from agentic_ai_system.data_ingestion import load_data, add_technical_indicators
28
+ from agentic_ai_system.alpaca_broker import AlpacaBroker
29
+ from agentic_ai_system.finrl_agent import FinRLAgent, FinRLConfig
30
+
31
+ class TradingWebSocketServer:
32
+ def __init__(self, host="localhost", port=8765):
33
+ self.host = host
34
+ self.port = port
35
+ self.clients = set()
36
+ self.config = None
37
+ self.alpaca_broker = None
38
+ self.finrl_agent = None
39
+ self.trading_active = False
40
+ self.market_data = None
41
+ self.portfolio_data = {}
42
+
43
+ # Setup logging
44
+ logging.basicConfig(level=logging.INFO)
45
+ self.logger = logging.getLogger(__name__)
46
+
47
+ async def register(self, websocket):
48
+ """Register a new client"""
49
+ self.clients.add(websocket)
50
+ self.logger.info(f"Client connected. Total clients: {len(self.clients)}")
51
+
52
+ # Send initial data
53
+ await self.send_initial_data(websocket)
54
+
55
+ async def unregister(self, websocket):
56
+ """Unregister a client"""
57
+ self.clients.remove(websocket)
58
+ self.logger.info(f"Client disconnected. Total clients: {len(self.clients)}")
59
+
60
+ async def send_initial_data(self, websocket):
61
+ """Send initial data to new client"""
62
+ initial_data = {
63
+ "type": "initial_data",
64
+ "timestamp": datetime.now().isoformat(),
65
+ "config": self.config,
66
+ "portfolio": self.portfolio_data,
67
+ "trading_status": self.trading_active
68
+ }
69
+ await websocket.send(json.dumps(initial_data))
70
+
71
+ async def broadcast(self, message):
72
+ """Broadcast message to all connected clients"""
73
+ if self.clients:
74
+ message_str = json.dumps(message)
75
+ await asyncio.gather(
76
+ *[client.send(message_str) for client in self.clients],
77
+ return_exceptions=True
78
+ )
79
+
80
+ async def handle_market_data(self):
81
+ """Handle real-time market data updates"""
82
+ while True:
83
+ try:
84
+ if self.config and self.alpaca_broker:
85
+ # Get real-time market data
86
+ symbol = self.config['trading']['symbol']
87
+
88
+ # Get current price
89
+ current_price = await self.get_current_price(symbol)
90
+
91
+ if current_price:
92
+ market_update = {
93
+ "type": "market_data",
94
+ "timestamp": datetime.now().isoformat(),
95
+ "symbol": symbol,
96
+ "price": current_price,
97
+ "volume": await self.get_current_volume(symbol)
98
+ }
99
+
100
+ await self.broadcast(market_update)
101
+ self.logger.info(f"Broadcasted market data for {symbol}: ${current_price}")
102
+
103
+ await asyncio.sleep(1) # Update every second
104
+
105
+ except Exception as e:
106
+ self.logger.error(f"Error in market data handler: {e}")
107
+ await asyncio.sleep(5) # Wait before retrying
108
+
109
+ async def handle_portfolio_updates(self):
110
+ """Handle portfolio updates"""
111
+ while True:
112
+ try:
113
+ if self.alpaca_broker:
114
+ # Get portfolio information
115
+ account_info = self.alpaca_broker.get_account_info()
116
+ positions = self.alpaca_broker.get_positions()
117
+
118
+ if account_info:
119
+ portfolio_update = {
120
+ "type": "portfolio_update",
121
+ "timestamp": datetime.now().isoformat(),
122
+ "account": {
123
+ "buying_power": float(account_info['buying_power']),
124
+ "portfolio_value": float(account_info['portfolio_value']),
125
+ "equity": float(account_info['equity']),
126
+ "cash": float(account_info['cash'])
127
+ },
128
+ "positions": positions if positions else []
129
+ }
130
+
131
+ await self.broadcast(portfolio_update)
132
+ self.portfolio_data = portfolio_update
133
+
134
+ await asyncio.sleep(5) # Update every 5 seconds
135
+
136
+ except Exception as e:
137
+ self.logger.error(f"Error in portfolio updates: {e}")
138
+ await asyncio.sleep(10) # Wait before retrying
139
+
140
+ async def handle_trading_signals(self):
141
+ """Handle trading signals from FinRL agent"""
142
+ while True:
143
+ try:
144
+ if self.trading_active and self.finrl_agent and self.market_data is not None:
145
+ # Generate trading signals
146
+ signal = await self.generate_trading_signal()
147
+
148
+ if signal:
149
+ signal_update = {
150
+ "type": "trading_signal",
151
+ "timestamp": datetime.now().isoformat(),
152
+ "signal": signal
153
+ }
154
+
155
+ await self.broadcast(signal_update)
156
+ self.logger.info(f"Broadcasted trading signal: {signal}")
157
+
158
+ await asyncio.sleep(10) # Generate signals every 10 seconds
159
+
160
+ except Exception as e:
161
+ self.logger.error(f"Error in trading signals: {e}")
162
+ await asyncio.sleep(30) # Wait before retrying
163
+
164
+ async def get_current_price(self, symbol):
165
+ """Get current price for symbol"""
166
+ try:
167
+ if self.alpaca_broker:
168
+ # Get latest price from Alpaca
169
+ latest_trade = self.alpaca_broker.get_latest_trade(symbol)
170
+ if latest_trade:
171
+ return float(latest_trade['p'])
172
+ return None
173
+ except Exception as e:
174
+ self.logger.error(f"Error getting current price: {e}")
175
+ return None
176
+
177
+ async def get_current_volume(self, symbol):
178
+ """Get current volume for symbol"""
179
+ try:
180
+ if self.alpaca_broker:
181
+ # Get latest trade volume
182
+ latest_trade = self.alpaca_broker.get_latest_trade(symbol)
183
+ if latest_trade:
184
+ return int(latest_trade['s'])
185
+ return None
186
+ except Exception as e:
187
+ self.logger.error(f"Error getting current volume: {e}")
188
+ return None
189
+
190
+ async def generate_trading_signal(self):
191
+ """Generate trading signal using FinRL agent"""
192
+ try:
193
+ if self.finrl_agent and self.market_data is not None:
194
+ # Use recent data for prediction
195
+ recent_data = self.market_data.tail(100)
196
+
197
+ prediction_result = self.finrl_agent.predict(
198
+ data=recent_data,
199
+ config=self.config,
200
+ use_real_broker=False
201
+ )
202
+
203
+ if prediction_result['success']:
204
+ # Generate signal based on prediction
205
+ current_price = await self.get_current_price(self.config['trading']['symbol'])
206
+
207
+ if current_price:
208
+ signal = {
209
+ "action": "HOLD", # Default action
210
+ "confidence": 0.5,
211
+ "price": current_price,
212
+ "reasoning": "Model prediction"
213
+ }
214
+
215
+ # Determine action based on prediction
216
+ if prediction_result['total_return'] > 0.02: # 2% positive return
217
+ signal["action"] = "BUY"
218
+ signal["confidence"] = min(0.9, 0.5 + abs(prediction_result['total_return']))
219
+ elif prediction_result['total_return'] < -0.02: # 2% negative return
220
+ signal["action"] = "SELL"
221
+ signal["confidence"] = min(0.9, 0.5 + abs(prediction_result['total_return']))
222
+
223
+ return signal
224
+
225
+ return None
226
+ except Exception as e:
227
+ self.logger.error(f"Error generating trading signal: {e}")
228
+ return None
229
+
230
+ async def handle_client_message(self, websocket, message):
231
+ """Handle incoming client messages"""
232
+ try:
233
+ data = json.loads(message)
234
+ message_type = data.get("type")
235
+
236
+ if message_type == "load_config":
237
+ # Load configuration
238
+ config_file = data.get("config_file", "config.yaml")
239
+ self.config = load_config(config_file)
240
+
241
+ response = {
242
+ "type": "config_loaded",
243
+ "success": True,
244
+ "config": self.config
245
+ }
246
+ await websocket.send(json.dumps(response))
247
+
248
+ elif message_type == "connect_alpaca":
249
+ # Connect to Alpaca
250
+ api_key = data.get("api_key")
251
+ secret_key = data.get("secret_key")
252
+
253
+ if api_key and secret_key:
254
+ self.config['alpaca']['api_key'] = api_key
255
+ self.config['alpaca']['secret_key'] = secret_key
256
+ self.config['execution']['broker_api'] = 'alpaca_paper'
257
+
258
+ self.alpaca_broker = AlpacaBroker(self.config)
259
+
260
+ response = {
261
+ "type": "alpaca_connected",
262
+ "success": True
263
+ }
264
+ await websocket.send(json.dumps(response))
265
+ else:
266
+ response = {
267
+ "type": "alpaca_connected",
268
+ "success": False,
269
+ "error": "Missing API credentials"
270
+ }
271
+ await websocket.send(json.dumps(response))
272
+
273
+ elif message_type == "start_trading":
274
+ # Start trading
275
+ self.trading_active = True
276
+
277
+ response = {
278
+ "type": "trading_started",
279
+ "success": True
280
+ }
281
+ await websocket.send(json.dumps(response))
282
+
283
+ # Broadcast to all clients
284
+ await self.broadcast({
285
+ "type": "trading_status",
286
+ "active": True,
287
+ "timestamp": datetime.now().isoformat()
288
+ })
289
+
290
+ elif message_type == "stop_trading":
291
+ # Stop trading
292
+ self.trading_active = False
293
+
294
+ response = {
295
+ "type": "trading_stopped",
296
+ "success": True
297
+ }
298
+ await websocket.send(json.dumps(response))
299
+
300
+ # Broadcast to all clients
301
+ await self.broadcast({
302
+ "type": "trading_status",
303
+ "active": False,
304
+ "timestamp": datetime.now().isoformat()
305
+ })
306
+
307
+ elif message_type == "load_data":
308
+ # Load market data
309
+ if self.config:
310
+ self.market_data = load_data(self.config)
311
+ if self.market_data is not None:
312
+ self.market_data = add_technical_indicators(self.market_data)
313
+
314
+ response = {
315
+ "type": "data_loaded",
316
+ "success": True,
317
+ "data_points": len(self.market_data)
318
+ }
319
+ else:
320
+ response = {
321
+ "type": "data_loaded",
322
+ "success": False,
323
+ "error": "Failed to load data"
324
+ }
325
+ else:
326
+ response = {
327
+ "type": "data_loaded",
328
+ "success": False,
329
+ "error": "Configuration not loaded"
330
+ }
331
+
332
+ await websocket.send(json.dumps(response))
333
+
334
+ elif message_type == "train_model":
335
+ # Train FinRL model
336
+ if self.market_data is not None:
337
+ algorithm = data.get("algorithm", "PPO")
338
+ learning_rate = data.get("learning_rate", 0.0003)
339
+ training_steps = data.get("training_steps", 100000)
340
+
341
+ finrl_config = FinRLConfig(
342
+ algorithm=algorithm,
343
+ learning_rate=learning_rate,
344
+ batch_size=64,
345
+ buffer_size=1000000,
346
+ learning_starts=100,
347
+ gamma=0.99,
348
+ tau=0.005,
349
+ train_freq=1,
350
+ gradient_steps=1,
351
+ verbose=1,
352
+ tensorboard_log='logs/finrl_tensorboard'
353
+ )
354
+
355
+ self.finrl_agent = FinRLAgent(finrl_config)
356
+
357
+ # Train in background thread
358
+ def train_model():
359
+ try:
360
+ result = self.finrl_agent.train(
361
+ data=self.market_data,
362
+ config=self.config,
363
+ total_timesteps=training_steps,
364
+ use_real_broker=False
365
+ )
366
+
367
+ # Broadcast training completion
368
+ asyncio.create_task(self.broadcast({
369
+ "type": "training_completed",
370
+ "success": result['success'],
371
+ "result": result
372
+ }))
373
+ except Exception as e:
374
+ asyncio.create_task(self.broadcast({
375
+ "type": "training_completed",
376
+ "success": False,
377
+ "error": str(e)
378
+ }))
379
+
380
+ training_thread = threading.Thread(target=train_model)
381
+ training_thread.daemon = True
382
+ training_thread.start()
383
+
384
+ response = {
385
+ "type": "training_started",
386
+ "success": True
387
+ }
388
+ else:
389
+ response = {
390
+ "type": "training_started",
391
+ "success": False,
392
+ "error": "Market data not loaded"
393
+ }
394
+
395
+ await websocket.send(json.dumps(response))
396
+
397
+ else:
398
+ # Unknown message type
399
+ response = {
400
+ "type": "error",
401
+ "message": f"Unknown message type: {message_type}"
402
+ }
403
+ await websocket.send(json.dumps(response))
404
+
405
+ except json.JSONDecodeError:
406
+ response = {
407
+ "type": "error",
408
+ "message": "Invalid JSON message"
409
+ }
410
+ await websocket.send(json.dumps(response))
411
+ except Exception as e:
412
+ response = {
413
+ "type": "error",
414
+ "message": f"Server error: {str(e)}"
415
+ }
416
+ await websocket.send(json.dumps(response))
417
+
418
+ async def websocket_handler(self, websocket, path):
419
+ """Main WebSocket handler"""
420
+ await self.register(websocket)
421
+ try:
422
+ async for message in websocket:
423
+ await self.handle_client_message(websocket, message)
424
+ except websockets.exceptions.ConnectionClosed:
425
+ pass
426
+ finally:
427
+ await self.unregister(websocket)
428
+
429
+ async def start_server(self):
430
+ """Start the WebSocket server"""
431
+ # Start background tasks
432
+ asyncio.create_task(self.handle_market_data())
433
+ asyncio.create_task(self.handle_portfolio_updates())
434
+ asyncio.create_task(self.handle_trading_signals())
435
+
436
+ # Start WebSocket server
437
+ server = await websockets.serve(
438
+ self.websocket_handler,
439
+ self.host,
440
+ self.port
441
+ )
442
+
443
+ self.logger.info(f"WebSocket server started on ws://{self.host}:{self.port}")
444
+
445
+ # Keep server running
446
+ await server.wait_closed()
447
+
448
+ def run_server(self):
449
+ """Run the server in a separate thread"""
450
+ def run():
451
+ asyncio.run(self.start_server())
452
+
453
+ server_thread = threading.Thread(target=run)
454
+ server_thread.daemon = True
455
+ server_thread.start()
456
+
457
+ return server_thread
458
+
459
+ def create_websocket_server(host="localhost", port=8765):
460
+ """Create and return a WebSocket server instance"""
461
+ return TradingWebSocketServer(host=host, port=port)
ui_launcher.py ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ UI Launcher for Algorithmic Trading System
4
+
5
+ Provides multiple UI options:
6
+ - Streamlit: Quick prototyping and data science workflows
7
+ - Dash: Enterprise-grade interactive dashboards
8
+ - Jupyter: Notebook-based interfaces
9
+ - WebSocket: Real-time trading interfaces
10
+ """
11
+
12
+ import argparse
13
+ import sys
14
+ import os
15
+ import subprocess
16
+ import webbrowser
17
+ import time
18
+ import threading
19
+ from typing import Optional
20
+
21
+ def check_dependencies():
22
+ """Check if required UI dependencies are installed"""
23
+ required_packages = [
24
+ 'streamlit',
25
+ 'dash',
26
+ 'plotly',
27
+ 'ipywidgets'
28
+ ]
29
+
30
+ missing_packages = []
31
+ for package in required_packages:
32
+ try:
33
+ __import__(package)
34
+ except ImportError:
35
+ missing_packages.append(package)
36
+
37
+ if missing_packages:
38
+ print(f"❌ Missing required packages: {', '.join(missing_packages)}")
39
+ print("Please install them using: pip install -r requirements.txt")
40
+ return False
41
+
42
+ return True
43
+
44
+ def launch_streamlit():
45
+ """Launch Streamlit application"""
46
+ print("πŸš€ Launching Streamlit UI...")
47
+
48
+ # Create streamlit app file if it doesn't exist
49
+ streamlit_app_path = "ui/streamlit_app.py"
50
+ if not os.path.exists(streamlit_app_path):
51
+ print(f"❌ Streamlit app not found at {streamlit_app_path}")
52
+ return False
53
+
54
+ try:
55
+ # Launch Streamlit
56
+ cmd = [
57
+ sys.executable, "-m", "streamlit", "run",
58
+ streamlit_app_path,
59
+ "--server.port", "8501",
60
+ "--server.address", "0.0.0.0",
61
+ "--browser.gatherUsageStats", "false"
62
+ ]
63
+
64
+ print(f"Running: {' '.join(cmd)}")
65
+ subprocess.run(cmd)
66
+ return True
67
+
68
+ except Exception as e:
69
+ print(f"❌ Error launching Streamlit: {e}")
70
+ return False
71
+
72
+ def launch_dash():
73
+ """Launch Dash application"""
74
+ print("πŸš€ Launching Dash UI...")
75
+
76
+ # Create dash app file if it doesn't exist
77
+ dash_app_path = "ui/dash_app.py"
78
+ if not os.path.exists(dash_app_path):
79
+ print(f"❌ Dash app not found at {dash_app_path}")
80
+ return False
81
+
82
+ try:
83
+ # Launch Dash
84
+ cmd = [
85
+ sys.executable, dash_app_path
86
+ ]
87
+
88
+ print(f"Running: {' '.join(cmd)}")
89
+ subprocess.run(cmd)
90
+ return True
91
+
92
+ except Exception as e:
93
+ print(f"❌ Error launching Dash: {e}")
94
+ return False
95
+
96
+ def launch_jupyter():
97
+ """Launch Jupyter interface"""
98
+ print("πŸš€ Launching Jupyter UI...")
99
+
100
+ try:
101
+ # Launch Jupyter Lab
102
+ cmd = [
103
+ sys.executable, "-m", "jupyter", "lab",
104
+ "--port", "8888",
105
+ "--ip", "0.0.0.0",
106
+ "--no-browser"
107
+ ]
108
+
109
+ print(f"Running: {' '.join(cmd)}")
110
+ subprocess.run(cmd)
111
+ return True
112
+
113
+ except Exception as e:
114
+ print(f"❌ Error launching Jupyter: {e}")
115
+ return False
116
+
117
+ def launch_websocket_server():
118
+ """Launch WebSocket server"""
119
+ print("πŸš€ Launching WebSocket Server...")
120
+
121
+ try:
122
+ from ui.websocket_server import create_websocket_server
123
+
124
+ server = create_websocket_server(host="0.0.0.0", port=8765)
125
+ server_thread = server.run_server()
126
+
127
+ print("βœ… WebSocket server started on ws://0.0.0.0:8765")
128
+ print("Press Ctrl+C to stop the server")
129
+
130
+ # Keep the main thread alive
131
+ try:
132
+ while True:
133
+ time.sleep(1)
134
+ except KeyboardInterrupt:
135
+ print("\nπŸ›‘ Stopping WebSocket server...")
136
+
137
+ return True
138
+
139
+ except Exception as e:
140
+ print(f"❌ Error launching WebSocket server: {e}")
141
+ return False
142
+
143
+ def open_browser(url: str, delay: int = 2):
144
+ """Open browser after delay"""
145
+ def open_url():
146
+ time.sleep(delay)
147
+ try:
148
+ webbrowser.open(url)
149
+ print(f"🌐 Opened browser to: {url}")
150
+ except Exception as e:
151
+ print(f"⚠️ Could not open browser: {e}")
152
+
153
+ browser_thread = threading.Thread(target=open_url)
154
+ browser_thread.daemon = True
155
+ browser_thread.start()
156
+
157
+ def main():
158
+ """Main launcher function"""
159
+ parser = argparse.ArgumentParser(
160
+ description="UI Launcher for Algorithmic Trading System",
161
+ formatter_class=argparse.RawDescriptionHelpFormatter,
162
+ epilog="""
163
+ Examples:
164
+ python ui_launcher.py streamlit # Launch Streamlit UI
165
+ python ui_launcher.py dash # Launch Dash UI
166
+ python ui_launcher.py jupyter # Launch Jupyter Lab
167
+ python ui_launcher.py websocket # Launch WebSocket server
168
+ python ui_launcher.py all # Launch all UIs
169
+ """
170
+ )
171
+
172
+ parser.add_argument(
173
+ "ui_type",
174
+ choices=["streamlit", "dash", "jupyter", "websocket", "all"],
175
+ help="Type of UI to launch"
176
+ )
177
+
178
+ parser.add_argument(
179
+ "--no-browser",
180
+ action="store_true",
181
+ help="Don't automatically open browser"
182
+ )
183
+
184
+ parser.add_argument(
185
+ "--port",
186
+ type=int,
187
+ help="Custom port number (overrides default)"
188
+ )
189
+
190
+ args = parser.parse_args()
191
+
192
+ # Check dependencies
193
+ if not check_dependencies():
194
+ sys.exit(1)
195
+
196
+ print("πŸ€– Algorithmic Trading System - UI Launcher")
197
+ print("=" * 50)
198
+
199
+ success = False
200
+
201
+ if args.ui_type == "streamlit":
202
+ success = launch_streamlit()
203
+ if success and not args.no_browser:
204
+ open_browser("http://localhost:8501")
205
+
206
+ elif args.ui_type == "dash":
207
+ success = launch_dash()
208
+ if success and not args.no_browser:
209
+ open_browser("http://localhost:8050")
210
+
211
+ elif args.ui_type == "jupyter":
212
+ success = launch_jupyter()
213
+ if success and not args.no_browser:
214
+ open_browser("http://localhost:8888")
215
+
216
+ elif args.ui_type == "websocket":
217
+ success = launch_websocket_server()
218
+
219
+ elif args.ui_type == "all":
220
+ print("πŸš€ Launching all UI interfaces...")
221
+
222
+ # Launch WebSocket server in background
223
+ websocket_thread = threading.Thread(target=launch_websocket_server)
224
+ websocket_thread.daemon = True
225
+ websocket_thread.start()
226
+
227
+ # Launch Streamlit
228
+ streamlit_thread = threading.Thread(target=launch_streamlit)
229
+ streamlit_thread.daemon = True
230
+ streamlit_thread.start()
231
+
232
+ # Launch Dash
233
+ dash_thread = threading.Thread(target=launch_dash)
234
+ dash_thread.daemon = True
235
+ dash_thread.start()
236
+
237
+ # Launch Jupyter
238
+ jupyter_thread = threading.Thread(target=launch_jupyter)
239
+ jupyter_thread.daemon = True
240
+ jupyter_thread.start()
241
+
242
+ if not args.no_browser:
243
+ open_browser("http://localhost:8501", 3) # Streamlit
244
+ open_browser("http://localhost:8050", 5) # Dash
245
+ open_browser("http://localhost:8888", 7) # Jupyter
246
+
247
+ print("βœ… All UIs launched!")
248
+ print("πŸ“Š Streamlit: http://localhost:8501")
249
+ print("πŸ“ˆ Dash: http://localhost:8050")
250
+ print("πŸ““ Jupyter: http://localhost:8888")
251
+ print("πŸ”Œ WebSocket: ws://localhost:8765")
252
+
253
+ # Keep main thread alive
254
+ try:
255
+ while True:
256
+ time.sleep(1)
257
+ except KeyboardInterrupt:
258
+ print("\nπŸ›‘ Stopping all UIs...")
259
+
260
+ success = True
261
+
262
+ if success:
263
+ print("βœ… UI launched successfully!")
264
+ else:
265
+ print("❌ Failed to launch UI")
266
+ sys.exit(1)
267
+
268
+ if __name__ == "__main__":
269
+ main()