deltafq 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of deltafq might be problematic. Click here for more details.

Files changed (60) hide show
  1. deltafq/__init__.py +30 -31
  2. deltafq/backtest/__init__.py +17 -7
  3. deltafq/backtest/engine.py +99 -52
  4. deltafq/backtest/metrics.py +113 -0
  5. deltafq/backtest/performance.py +81 -0
  6. deltafq/backtest/reporter.py +91 -0
  7. deltafq/core/__init__.py +19 -0
  8. deltafq/core/base.py +37 -0
  9. deltafq/core/config.py +63 -0
  10. deltafq/core/exceptions.py +35 -0
  11. deltafq/core/logger.py +46 -0
  12. deltafq/data/__init__.py +17 -7
  13. deltafq/data/cleaner.py +41 -0
  14. deltafq/data/fetcher.py +52 -0
  15. deltafq/data/storage.py +56 -0
  16. deltafq/data/validator.py +52 -0
  17. deltafq/indicators/__init__.py +17 -8
  18. deltafq/indicators/momentum.py +56 -23
  19. deltafq/indicators/technical.py +59 -0
  20. deltafq/indicators/trend.py +129 -61
  21. deltafq/indicators/volatility.py +67 -27
  22. deltafq/live/__init__.py +17 -0
  23. deltafq/live/connection.py +235 -0
  24. deltafq/live/data_feed.py +159 -0
  25. deltafq/live/monitoring.py +192 -0
  26. deltafq/live/risk_control.py +193 -0
  27. deltafq/strategy/__init__.py +17 -6
  28. deltafq/strategy/base_strategy.py +53 -0
  29. deltafq/strategy/portfolio.py +82 -0
  30. deltafq/strategy/risk_manager.py +64 -0
  31. deltafq/strategy/signal_generator.py +52 -0
  32. deltafq/trading/__init__.py +19 -0
  33. deltafq/trading/broker.py +119 -0
  34. deltafq/trading/execution.py +176 -0
  35. deltafq/trading/order_manager.py +111 -0
  36. deltafq/trading/position_manager.py +157 -0
  37. deltafq/trading/simulator.py +150 -0
  38. deltafq-0.1.2.dist-info/METADATA +110 -0
  39. deltafq-0.1.2.dist-info/RECORD +43 -0
  40. deltafq-0.1.2.dist-info/entry_points.txt +2 -0
  41. {deltafq-0.1.1.dist-info → deltafq-0.1.2.dist-info}/licenses/LICENSE +21 -22
  42. deltafq/backtest/result.py +0 -45
  43. deltafq/data/base.py +0 -30
  44. deltafq/data/loader.py +0 -63
  45. deltafq/optimization/__init__.py +0 -6
  46. deltafq/optimization/grid_search.py +0 -41
  47. deltafq/performance/__init__.py +0 -6
  48. deltafq/performance/metrics.py +0 -37
  49. deltafq/risk/__init__.py +0 -7
  50. deltafq/risk/metrics.py +0 -33
  51. deltafq/risk/position.py +0 -39
  52. deltafq/strategy/base.py +0 -44
  53. deltafq/trade/__init__.py +0 -6
  54. deltafq/trade/broker.py +0 -40
  55. deltafq/utils/__init__.py +0 -6
  56. deltafq/utils/time.py +0 -32
  57. deltafq-0.1.1.dist-info/METADATA +0 -202
  58. deltafq-0.1.1.dist-info/RECORD +0 -29
  59. {deltafq-0.1.1.dist-info → deltafq-0.1.2.dist-info}/WHEEL +0 -0
  60. {deltafq-0.1.1.dist-info → deltafq-0.1.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,192 @@
1
+ """
2
+ Trading monitoring and alerts for live trading.
3
+ """
4
+
5
+ import pandas as pd
6
+ from typing import Dict, List, Any, Optional, Callable
7
+ from datetime import datetime, timedelta
8
+ from ..core.base import BaseComponent
9
+
10
+
11
+ class TradingMonitor(BaseComponent):
12
+ """Monitor trading activities and generate alerts."""
13
+
14
+ def __init__(self, **kwargs):
15
+ """Initialize trading monitor."""
16
+ super().__init__(**kwargs)
17
+ self.alerts = []
18
+ self.monitoring_rules = {}
19
+ self.alert_callbacks = []
20
+ self.monitoring_active = False
21
+
22
+ def initialize(self) -> bool:
23
+ """Initialize trading monitor."""
24
+ self.logger.info("Initializing trading monitor")
25
+ return True
26
+
27
+ def add_monitoring_rule(self, rule_name: str, rule_func: Callable,
28
+ threshold: float = None, **kwargs) -> bool:
29
+ """Add a monitoring rule."""
30
+ try:
31
+ self.monitoring_rules[rule_name] = {
32
+ 'function': rule_func,
33
+ 'threshold': threshold,
34
+ 'parameters': kwargs,
35
+ 'active': True,
36
+ 'last_triggered': None
37
+ }
38
+
39
+ self.logger.info(f"Added monitoring rule: {rule_name}")
40
+ return True
41
+
42
+ except Exception as e:
43
+ self.logger.error(f"Failed to add monitoring rule: {str(e)}")
44
+ return False
45
+
46
+ def add_alert_callback(self, callback: Callable) -> bool:
47
+ """Add alert callback function."""
48
+ self.alert_callbacks.append(callback)
49
+ return True
50
+
51
+ def start_monitoring(self) -> bool:
52
+ """Start monitoring."""
53
+ try:
54
+ self.monitoring_active = True
55
+ self.logger.info("Trading monitoring started")
56
+
57
+ # In a real implementation, this would start a monitoring loop
58
+ # For now, we'll provide the framework
59
+
60
+ return True
61
+
62
+ except Exception as e:
63
+ self.monitoring_active = False
64
+ self.logger.error(f"Failed to start monitoring: {str(e)}")
65
+ return False
66
+
67
+ def stop_monitoring(self) -> bool:
68
+ """Stop monitoring."""
69
+ try:
70
+ self.monitoring_active = False
71
+ self.logger.info("Trading monitoring stopped")
72
+ return True
73
+
74
+ except Exception as e:
75
+ self.logger.error(f"Failed to stop monitoring: {str(e)}")
76
+ return False
77
+
78
+ def check_rule(self, rule_name: str, data: Dict[str, Any]) -> bool:
79
+ """Check a specific monitoring rule."""
80
+ if rule_name not in self.monitoring_rules:
81
+ return False
82
+
83
+ rule = self.monitoring_rules[rule_name]
84
+ if not rule['active']:
85
+ return False
86
+
87
+ try:
88
+ # Execute the rule function
89
+ result = rule['function'](data, rule['threshold'], **rule['parameters'])
90
+
91
+ # Check if rule was triggered
92
+ if result:
93
+ self._trigger_alert(rule_name, data, result)
94
+ rule['last_triggered'] = datetime.now()
95
+ return True
96
+
97
+ return False
98
+
99
+ except Exception as e:
100
+ self.logger.error(f"Rule check failed for {rule_name}: {str(e)}")
101
+ return False
102
+
103
+ def check_all_rules(self, data: Dict[str, Any]) -> Dict[str, bool]:
104
+ """Check all active monitoring rules."""
105
+ results = {}
106
+
107
+ for rule_name in self.monitoring_rules:
108
+ if self.monitoring_rules[rule_name]['active']:
109
+ results[rule_name] = self.check_rule(rule_name, data)
110
+
111
+ return results
112
+
113
+ def _trigger_alert(self, rule_name: str, data: Dict[str, Any], result: Any):
114
+ """Trigger an alert."""
115
+ alert = {
116
+ 'rule_name': rule_name,
117
+ 'timestamp': datetime.now(),
118
+ 'data': data,
119
+ 'result': result,
120
+ 'severity': self._determine_severity(rule_name, result)
121
+ }
122
+
123
+ self.alerts.append(alert)
124
+ self.logger.warning(f"Alert triggered: {rule_name}")
125
+
126
+ # Notify alert callbacks
127
+ for callback in self.alert_callbacks:
128
+ try:
129
+ callback(alert)
130
+ except Exception as e:
131
+ self.logger.error(f"Alert callback failed: {str(e)}")
132
+
133
+ def _determine_severity(self, rule_name: str, result: Any) -> str:
134
+ """Determine alert severity."""
135
+ # Simple severity determination based on rule name
136
+ if 'loss' in rule_name.lower() or 'drawdown' in rule_name.lower():
137
+ return 'HIGH'
138
+ elif 'position' in rule_name.lower() or 'concentration' in rule_name.lower():
139
+ return 'MEDIUM'
140
+ else:
141
+ return 'LOW'
142
+
143
+ def get_alerts(self, hours: int = 24) -> List[Dict[str, Any]]:
144
+ """Get alerts from the last N hours."""
145
+ cutoff_time = datetime.now() - timedelta(hours=hours)
146
+ return [alert for alert in self.alerts if alert['timestamp'] > cutoff_time]
147
+
148
+ def clear_alerts(self, hours: int = None) -> int:
149
+ """Clear old alerts."""
150
+ if hours is None:
151
+ # Clear all alerts
152
+ count = len(self.alerts)
153
+ self.alerts.clear()
154
+ else:
155
+ # Clear alerts older than specified hours
156
+ cutoff_time = datetime.now() - timedelta(hours=hours)
157
+ original_count = len(self.alerts)
158
+ self.alerts = [alert for alert in self.alerts if alert['timestamp'] > cutoff_time]
159
+ count = original_count - len(self.alerts)
160
+
161
+ self.logger.info(f"Cleared {count} alerts")
162
+ return count
163
+
164
+ def enable_rule(self, rule_name: str) -> bool:
165
+ """Enable a monitoring rule."""
166
+ if rule_name in self.monitoring_rules:
167
+ self.monitoring_rules[rule_name]['active'] = True
168
+ return True
169
+ return False
170
+
171
+ def disable_rule(self, rule_name: str) -> bool:
172
+ """Disable a monitoring rule."""
173
+ if rule_name in self.monitoring_rules:
174
+ self.monitoring_rules[rule_name]['active'] = False
175
+ return True
176
+ return False
177
+
178
+ def get_monitoring_status(self) -> Dict[str, Any]:
179
+ """Get monitoring status."""
180
+ return {
181
+ 'monitoring_active': self.monitoring_active,
182
+ 'total_rules': len(self.monitoring_rules),
183
+ 'active_rules': sum(1 for rule in self.monitoring_rules.values() if rule['active']),
184
+ 'total_alerts': len(self.alerts),
185
+ 'recent_alerts': len(self.get_alerts(hours=1)),
186
+ 'rules': {name: {
187
+ 'active': rule['active'],
188
+ 'last_triggered': rule['last_triggered']
189
+ } for name, rule in self.monitoring_rules.items()}
190
+ }
191
+
192
+
@@ -0,0 +1,193 @@
1
+ """
2
+ Real-time risk control for live trading.
3
+ """
4
+
5
+ from typing import Dict, Any, Optional, List
6
+ from datetime import datetime, timedelta
7
+ from ..core.base import BaseComponent
8
+ from ..core.exceptions import TradingError
9
+
10
+
11
+ class LiveRiskControl(BaseComponent):
12
+ """Real-time risk control system."""
13
+
14
+ def __init__(self, max_position_size: float = 0.1, max_daily_loss: float = 0.05,
15
+ max_drawdown: float = 0.15, **kwargs):
16
+ """Initialize risk control."""
17
+ super().__init__(**kwargs)
18
+ self.max_position_size = max_position_size
19
+ self.max_daily_loss = max_daily_loss
20
+ self.max_drawdown = max_drawdown
21
+ self.daily_pnl = 0.0
22
+ self.peak_equity = 0.0
23
+ self.risk_limits = {}
24
+ self.alert_callbacks = []
25
+
26
+ def initialize(self) -> bool:
27
+ """Initialize risk control."""
28
+ self.logger.info("Initializing live risk control")
29
+ return True
30
+
31
+ def add_alert_callback(self, callback) -> bool:
32
+ """Add alert callback function."""
33
+ self.alert_callbacks.append(callback)
34
+ return True
35
+
36
+ def check_position_risk(self, symbol: str, quantity: float, portfolio_value: float,
37
+ current_price: float) -> bool:
38
+ """Check if position size is within risk limits."""
39
+ try:
40
+ position_value = abs(quantity) * current_price
41
+ position_ratio = position_value / portfolio_value
42
+
43
+ # Check maximum position size
44
+ if position_ratio > self.max_position_size:
45
+ self._trigger_alert("POSITION_SIZE_EXCEEDED", {
46
+ 'symbol': symbol,
47
+ 'position_ratio': position_ratio,
48
+ 'max_allowed': self.max_position_size
49
+ })
50
+ return False
51
+
52
+ # Check symbol-specific limits
53
+ if symbol in self.risk_limits:
54
+ symbol_limit = self.risk_limits[symbol]
55
+ if position_ratio > symbol_limit:
56
+ self._trigger_alert("SYMBOL_LIMIT_EXCEEDED", {
57
+ 'symbol': symbol,
58
+ 'position_ratio': position_ratio,
59
+ 'symbol_limit': symbol_limit
60
+ })
61
+ return False
62
+
63
+ return True
64
+
65
+ except Exception as e:
66
+ self.logger.error(f"Risk check failed: {str(e)}")
67
+ return False
68
+
69
+ def check_daily_loss_limit(self, current_equity: float, initial_equity: float) -> bool:
70
+ """Check if daily loss limit is exceeded."""
71
+ try:
72
+ daily_pnl = current_equity - initial_equity
73
+ daily_pnl_ratio = daily_pnl / initial_equity
74
+
75
+ if daily_pnl_ratio < -self.max_daily_loss:
76
+ self._trigger_alert("DAILY_LOSS_LIMIT_EXCEEDED", {
77
+ 'daily_pnl': daily_pnl,
78
+ 'daily_pnl_ratio': daily_pnl_ratio,
79
+ 'max_daily_loss': self.max_daily_loss
80
+ })
81
+ return False
82
+
83
+ return True
84
+
85
+ except Exception as e:
86
+ self.logger.error(f"Daily loss check failed: {str(e)}")
87
+ return False
88
+
89
+ def check_drawdown_limit(self, current_equity: float) -> bool:
90
+ """Check if maximum drawdown is exceeded."""
91
+ try:
92
+ if current_equity > self.peak_equity:
93
+ self.peak_equity = current_equity
94
+
95
+ if self.peak_equity > 0:
96
+ drawdown = (self.peak_equity - current_equity) / self.peak_equity
97
+
98
+ if drawdown > self.max_drawdown:
99
+ self._trigger_alert("DRAWDOWN_LIMIT_EXCEEDED", {
100
+ 'current_drawdown': drawdown,
101
+ 'max_drawdown': self.max_drawdown,
102
+ 'peak_equity': self.peak_equity,
103
+ 'current_equity': current_equity
104
+ })
105
+ return False
106
+
107
+ return True
108
+
109
+ except Exception as e:
110
+ self.logger.error(f"Drawdown check failed: {str(e)}")
111
+ return False
112
+
113
+ def check_concentration_risk(self, positions: Dict[str, float], portfolio_value: float) -> bool:
114
+ """Check portfolio concentration risk."""
115
+ try:
116
+ total_position_value = sum(abs(value) for value in positions.values())
117
+
118
+ if total_position_value > portfolio_value * 0.95: # 95% of portfolio
119
+ self._trigger_alert("CONCENTRATION_RISK_HIGH", {
120
+ 'total_position_value': total_position_value,
121
+ 'portfolio_value': portfolio_value,
122
+ 'concentration_ratio': total_position_value / portfolio_value
123
+ })
124
+ return False
125
+
126
+ return True
127
+
128
+ except Exception as e:
129
+ self.logger.error(f"Concentration risk check failed: {str(e)}")
130
+ return False
131
+
132
+ def set_symbol_limit(self, symbol: str, limit: float) -> bool:
133
+ """Set position size limit for specific symbol."""
134
+ try:
135
+ self.risk_limits[symbol] = limit
136
+ self.logger.info(f"Set risk limit for {symbol}: {limit:.2%}")
137
+ return True
138
+
139
+ except Exception as e:
140
+ self.logger.error(f"Failed to set symbol limit: {str(e)}")
141
+ return False
142
+
143
+ def comprehensive_risk_check(self, symbol: str, quantity: float, portfolio_value: float,
144
+ current_price: float, current_equity: float,
145
+ initial_equity: float, positions: Dict[str, float]) -> Dict[str, bool]:
146
+ """Perform comprehensive risk checks."""
147
+ results = {
148
+ 'position_risk': self.check_position_risk(symbol, quantity, portfolio_value, current_price),
149
+ 'daily_loss': self.check_daily_loss_limit(current_equity, initial_equity),
150
+ 'drawdown': self.check_drawdown_limit(current_equity),
151
+ 'concentration': self.check_concentration_risk(positions, portfolio_value)
152
+ }
153
+
154
+ # Overall risk check passes only if all individual checks pass
155
+ results['overall'] = all(results.values())
156
+
157
+ return results
158
+
159
+ def _trigger_alert(self, alert_type: str, details: Dict[str, Any]):
160
+ """Trigger risk alert."""
161
+ alert = {
162
+ 'type': alert_type,
163
+ 'timestamp': datetime.now(),
164
+ 'details': details
165
+ }
166
+
167
+ self.logger.warning(f"Risk alert: {alert_type}")
168
+
169
+ # Notify alert callbacks
170
+ for callback in self.alert_callbacks:
171
+ try:
172
+ callback(alert)
173
+ except Exception as e:
174
+ self.logger.error(f"Alert callback failed: {str(e)}")
175
+
176
+ def reset_daily_limits(self):
177
+ """Reset daily risk limits (call at start of trading day)."""
178
+ self.daily_pnl = 0.0
179
+ self.logger.info("Daily risk limits reset")
180
+
181
+ def get_risk_status(self) -> Dict[str, Any]:
182
+ """Get current risk status."""
183
+ return {
184
+ 'max_position_size': self.max_position_size,
185
+ 'max_daily_loss': self.max_daily_loss,
186
+ 'max_drawdown': self.max_drawdown,
187
+ 'current_daily_pnl': self.daily_pnl,
188
+ 'peak_equity': self.peak_equity,
189
+ 'symbol_limits': dict(self.risk_limits),
190
+ 'active_alerts': len(self.alert_callbacks)
191
+ }
192
+
193
+
@@ -1,6 +1,17 @@
1
- """策略框架模块"""
2
-
3
- from deltafq.strategy.base import Strategy
4
-
5
- __all__ = ["Strategy"]
6
-
1
+ """
2
+ Strategy module for DeltaFQ.
3
+ """
4
+
5
+ from .base_strategy import BaseStrategy
6
+ from .signal_generator import SignalGenerator
7
+ from .portfolio import Portfolio
8
+ from .risk_manager import RiskManager
9
+
10
+ __all__ = [
11
+ "BaseStrategy",
12
+ "SignalGenerator",
13
+ "Portfolio",
14
+ "RiskManager"
15
+ ]
16
+
17
+
@@ -0,0 +1,53 @@
1
+ """
2
+ Base strategy class for DeltaFQ.
3
+ """
4
+
5
+ import pandas as pd
6
+ from abc import ABC, abstractmethod
7
+ from typing import Dict, Any, Optional
8
+ from ..core.base import BaseComponent
9
+ from ..core.exceptions import StrategyError
10
+
11
+
12
+ class BaseStrategy(BaseComponent):
13
+ """Base class for all trading strategies."""
14
+
15
+ def __init__(self, name: str = None, **kwargs):
16
+ """Initialize base strategy."""
17
+ super().__init__(name=name, **kwargs)
18
+ self.signals = pd.DataFrame()
19
+ self.positions = pd.DataFrame()
20
+
21
+ def initialize(self) -> bool:
22
+ """Initialize the strategy."""
23
+ self.logger.info(f"Initializing strategy: {self.name}")
24
+ return True
25
+
26
+ @abstractmethod
27
+ def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
28
+ """Generate trading signals from market data."""
29
+ pass
30
+
31
+ def run(self, data: pd.DataFrame) -> Dict[str, Any]:
32
+ """Run the strategy on given data."""
33
+ try:
34
+ self.logger.info(f"Running strategy: {self.name}")
35
+ signals = self.generate_signals(data)
36
+ return {
37
+ "strategy_name": self.name,
38
+ "signals": signals,
39
+ "performance": self._calculate_performance(signals, data)
40
+ }
41
+ except Exception as e:
42
+ raise StrategyError(f"Strategy execution failed: {str(e)}")
43
+
44
+ def _calculate_performance(self, signals: pd.DataFrame, data: pd.DataFrame) -> Dict[str, float]:
45
+ """Calculate basic performance metrics."""
46
+ # Placeholder implementation
47
+ return {
48
+ "total_return": 0.0,
49
+ "sharpe_ratio": 0.0,
50
+ "max_drawdown": 0.0
51
+ }
52
+
53
+
@@ -0,0 +1,82 @@
1
+ """
2
+ Portfolio management for DeltaFQ.
3
+ """
4
+
5
+ import pandas as pd
6
+ from typing import Dict, List, Optional
7
+ from ..core.base import BaseComponent
8
+
9
+
10
+ class Portfolio(BaseComponent):
11
+ """Portfolio management system."""
12
+
13
+ def __init__(self, initial_capital: float = 100000, **kwargs):
14
+ """Initialize portfolio."""
15
+ super().__init__(**kwargs)
16
+ self.initial_capital = initial_capital
17
+ self.cash = initial_capital
18
+ self.positions = {}
19
+ self.trades = []
20
+
21
+ def initialize(self) -> bool:
22
+ """Initialize portfolio."""
23
+ self.logger.info(f"Initializing portfolio with capital: {self.initial_capital}")
24
+ return True
25
+
26
+ def get_position(self, symbol: str) -> float:
27
+ """Get current position for symbol."""
28
+ return self.positions.get(symbol, 0.0)
29
+
30
+ def get_portfolio_value(self, prices: Dict[str, float]) -> float:
31
+ """Calculate total portfolio value."""
32
+ total_value = self.cash
33
+ for symbol, quantity in self.positions.items():
34
+ if symbol in prices:
35
+ total_value += quantity * prices[symbol]
36
+ return total_value
37
+
38
+ def execute_trade(self, symbol: str, quantity: int, price: float, commission: float = 0.001):
39
+ """Execute a trade."""
40
+ cost = quantity * price * (1 + commission)
41
+
42
+ if quantity > 0: # Buy
43
+ if cost <= self.cash:
44
+ self.cash -= cost
45
+ self.positions[symbol] = self.positions.get(symbol, 0) + quantity
46
+ self.trades.append({
47
+ 'symbol': symbol,
48
+ 'quantity': quantity,
49
+ 'price': price,
50
+ 'type': 'buy',
51
+ 'timestamp': pd.Timestamp.now()
52
+ })
53
+ self.logger.info(f"Bought {quantity} shares of {symbol} at {price}")
54
+ else:
55
+ self.logger.warning(f"Insufficient cash for trade: {symbol}")
56
+ else: # Sell
57
+ quantity = abs(quantity)
58
+ if self.positions.get(symbol, 0) >= quantity:
59
+ self.cash += quantity * price * (1 - commission)
60
+ self.positions[symbol] -= quantity
61
+ self.trades.append({
62
+ 'symbol': symbol,
63
+ 'quantity': -quantity,
64
+ 'price': price,
65
+ 'type': 'sell',
66
+ 'timestamp': pd.Timestamp.now()
67
+ })
68
+ self.logger.info(f"Sold {quantity} shares of {symbol} at {price}")
69
+ else:
70
+ self.logger.warning(f"Insufficient position for trade: {symbol}")
71
+
72
+ def get_portfolio_summary(self, prices: Dict[str, float]) -> Dict[str, float]:
73
+ """Get portfolio summary."""
74
+ total_value = self.get_portfolio_value(prices)
75
+ return {
76
+ 'total_value': total_value,
77
+ 'cash': self.cash,
78
+ 'total_return': (total_value - self.initial_capital) / self.initial_capital,
79
+ 'positions': dict(self.positions)
80
+ }
81
+
82
+
@@ -0,0 +1,64 @@
1
+ """
2
+ Risk management for DeltaFQ.
3
+ """
4
+
5
+ from typing import Dict, Any, Optional
6
+ from ..core.base import BaseComponent
7
+
8
+
9
+ class RiskManager(BaseComponent):
10
+ """Risk management system."""
11
+
12
+ def __init__(self, max_position_size: float = 0.1, max_drawdown: float = 0.2, **kwargs):
13
+ """Initialize risk manager."""
14
+ super().__init__(**kwargs)
15
+ self.max_position_size = max_position_size
16
+ self.max_drawdown = max_drawdown
17
+ self.peak_value = 0.0
18
+
19
+ def initialize(self) -> bool:
20
+ """Initialize risk manager."""
21
+ self.logger.info("Initializing risk manager")
22
+ return True
23
+
24
+ def check_position_size(self, symbol: str, quantity: float, portfolio_value: float) -> bool:
25
+ """Check if position size is within limits."""
26
+ position_value = abs(quantity) * self._get_current_price(symbol)
27
+ position_ratio = position_value / portfolio_value
28
+
29
+ if position_ratio > self.max_position_size:
30
+ self.logger.warning(f"Position size exceeds limit: {symbol}")
31
+ return False
32
+ return True
33
+
34
+ def check_drawdown(self, current_value: float) -> bool:
35
+ """Check if drawdown is within limits."""
36
+ if current_value > self.peak_value:
37
+ self.peak_value = current_value
38
+
39
+ drawdown = (self.peak_value - current_value) / self.peak_value
40
+
41
+ if drawdown > self.max_drawdown:
42
+ self.logger.warning(f"Drawdown exceeds limit: {drawdown:.2%}")
43
+ return False
44
+ return True
45
+
46
+ def _get_current_price(self, symbol: str) -> float:
47
+ """Get current price for symbol (placeholder)."""
48
+ # This would be replaced with actual price fetching
49
+ return 100.0
50
+
51
+ def get_risk_metrics(self, portfolio_value: float) -> Dict[str, float]:
52
+ """Get current risk metrics."""
53
+ drawdown = 0.0
54
+ if self.peak_value > 0:
55
+ drawdown = (self.peak_value - portfolio_value) / self.peak_value
56
+
57
+ return {
58
+ 'current_drawdown': drawdown,
59
+ 'max_drawdown_limit': self.max_drawdown,
60
+ 'peak_value': self.peak_value,
61
+ 'max_position_size': self.max_position_size
62
+ }
63
+
64
+
@@ -0,0 +1,52 @@
1
+ """
2
+ Signal generator for trading strategies.
3
+ """
4
+
5
+ import pandas as pd
6
+ import numpy as np
7
+ from typing import Dict, Any
8
+ from ..core.base import BaseComponent
9
+
10
+
11
+ class SignalGenerator(BaseComponent):
12
+ """Generate trading signals from market data."""
13
+
14
+ def initialize(self) -> bool:
15
+ """Initialize signal generator."""
16
+ self.logger.info("Initializing signal generator")
17
+ return True
18
+
19
+ def moving_average_crossover(self, data: pd.DataFrame, fast_period: int = 10, slow_period: int = 20) -> pd.Series:
20
+ """Generate signals based on moving average crossover."""
21
+ if 'close' not in data.columns:
22
+ raise ValueError("Data must contain 'close' column")
23
+
24
+ # Calculate moving averages
25
+ fast_ma = data['close'].rolling(window=fast_period).mean()
26
+ slow_ma = data['close'].rolling(window=slow_period).mean()
27
+
28
+ # Generate signals: 1 for buy, -1 for sell, 0 for hold
29
+ signals = np.where(fast_ma > slow_ma, 1, np.where(fast_ma < slow_ma, -1, 0))
30
+
31
+ self.logger.info(f"Generated MA crossover signals: {fast_period}/{slow_period}")
32
+ return pd.Series(signals, index=data.index)
33
+
34
+ def rsi_signals(self, data: pd.DataFrame, period: int = 14, oversold: float = 30, overbought: float = 70) -> pd.Series:
35
+ """Generate signals based on RSI."""
36
+ if 'close' not in data.columns:
37
+ raise ValueError("Data must contain 'close' column")
38
+
39
+ # Calculate RSI (simplified)
40
+ delta = data['close'].diff()
41
+ gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
42
+ loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
43
+ rs = gain / loss
44
+ rsi = 100 - (100 / (1 + rs))
45
+
46
+ # Generate signals
47
+ signals = np.where(rsi < oversold, 1, np.where(rsi > overbought, -1, 0))
48
+
49
+ self.logger.info(f"Generated RSI signals: period={period}")
50
+ return pd.Series(signals, index=data.index)
51
+
52
+
@@ -0,0 +1,19 @@
1
+ """
2
+ Trading module for DeltaFQ.
3
+ """
4
+
5
+ from .simulator import PaperTradingSimulator
6
+ from .broker import Broker
7
+ from .order_manager import OrderManager
8
+ from .position_manager import PositionManager
9
+ from .execution import ExecutionEngine
10
+
11
+ __all__ = [
12
+ "PaperTradingSimulator",
13
+ "Broker",
14
+ "OrderManager",
15
+ "PositionManager",
16
+ "ExecutionEngine"
17
+ ]
18
+
19
+