deltafq 0.1.0__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.0.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.0.dist-info/METADATA +0 -195
  58. deltafq-0.1.0.dist-info/RECORD +0 -29
  59. {deltafq-0.1.0.dist-info → deltafq-0.1.2.dist-info}/WHEEL +0 -0
  60. {deltafq-0.1.0.dist-info → deltafq-0.1.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,119 @@
1
+ """
2
+ Broker interface for live trading.
3
+ """
4
+
5
+ import pandas as pd
6
+ from abc import ABC, abstractmethod
7
+ from typing import Dict, List, Optional, Any
8
+ from datetime import datetime
9
+ from ..core.base import BaseComponent
10
+ from ..core.exceptions import TradingError
11
+
12
+
13
+ class Broker(BaseComponent, ABC):
14
+ """Abstract broker interface for live trading."""
15
+
16
+ def initialize(self) -> bool:
17
+ """Initialize broker connection."""
18
+ self.logger.info("Initializing broker connection")
19
+ return self._connect()
20
+
21
+ @abstractmethod
22
+ def _connect(self) -> bool:
23
+ """Connect to broker."""
24
+ pass
25
+
26
+ @abstractmethod
27
+ def place_order(self, symbol: str, quantity: int, order_type: str,
28
+ price: Optional[float] = None) -> str:
29
+ """Place an order with the broker."""
30
+ pass
31
+
32
+ @abstractmethod
33
+ def cancel_order(self, order_id: str) -> bool:
34
+ """Cancel an order."""
35
+ pass
36
+
37
+ @abstractmethod
38
+ def get_order_status(self, order_id: str) -> Dict[str, Any]:
39
+ """Get order status."""
40
+ pass
41
+
42
+ @abstractmethod
43
+ def get_account_info(self) -> Dict[str, Any]:
44
+ """Get account information."""
45
+ pass
46
+
47
+ @abstractmethod
48
+ def get_positions(self) -> Dict[str, Dict[str, Any]]:
49
+ """Get current positions."""
50
+ pass
51
+
52
+ @abstractmethod
53
+ def get_current_price(self, symbol: str) -> float:
54
+ """Get current price for symbol."""
55
+ pass
56
+
57
+
58
+ class MockBroker(Broker):
59
+ """Mock broker for testing purposes."""
60
+
61
+ def __init__(self, **kwargs):
62
+ """Initialize mock broker."""
63
+ super().__init__(**kwargs)
64
+ self.orders = {}
65
+ self.positions = {}
66
+ self.account_balance = 100000
67
+ self.order_counter = 0
68
+
69
+ def _connect(self) -> bool:
70
+ """Mock connection."""
71
+ self.logger.info("Connected to mock broker")
72
+ return True
73
+
74
+ def place_order(self, symbol: str, quantity: int, order_type: str,
75
+ price: Optional[float] = None) -> str:
76
+ """Place a mock order."""
77
+ self.order_counter += 1
78
+ order_id = f"MOCK_{self.order_counter}"
79
+
80
+ self.orders[order_id] = {
81
+ 'symbol': symbol,
82
+ 'quantity': quantity,
83
+ 'order_type': order_type,
84
+ 'price': price,
85
+ 'status': 'pending',
86
+ 'timestamp': datetime.now()
87
+ }
88
+
89
+ self.logger.info(f"Mock order placed: {order_id}")
90
+ return order_id
91
+
92
+ def cancel_order(self, order_id: str) -> bool:
93
+ """Cancel a mock order."""
94
+ if order_id in self.orders:
95
+ self.orders[order_id]['status'] = 'cancelled'
96
+ self.logger.info(f"Mock order cancelled: {order_id}")
97
+ return True
98
+ return False
99
+
100
+ def get_order_status(self, order_id: str) -> Dict[str, Any]:
101
+ """Get mock order status."""
102
+ return self.orders.get(order_id, {})
103
+
104
+ def get_account_info(self) -> Dict[str, Any]:
105
+ """Get mock account info."""
106
+ return {
107
+ 'balance': self.account_balance,
108
+ 'buying_power': self.account_balance,
109
+ 'equity': self.account_balance
110
+ }
111
+
112
+ def get_positions(self) -> Dict[str, Dict[str, Any]]:
113
+ """Get mock positions."""
114
+ return self.positions
115
+
116
+ def get_current_price(self, symbol: str) -> float:
117
+ """Get mock current price."""
118
+ # Return a mock price
119
+ return 100.0
@@ -0,0 +1,176 @@
1
+ """
2
+ Trade execution engine for DeltaFQ.
3
+ """
4
+
5
+ import pandas as pd
6
+ from typing import Dict, List, Optional, Any
7
+ from ..core.base import BaseComponent
8
+ from ..core.exceptions import TradingError
9
+ from .order_manager import OrderManager
10
+ from .position_manager import PositionManager
11
+
12
+
13
+ class ExecutionEngine(BaseComponent):
14
+ """Trade execution engine."""
15
+
16
+ def __init__(self, broker=None, **kwargs):
17
+ """Initialize execution engine."""
18
+ super().__init__(**kwargs)
19
+ self.broker = broker
20
+ self.order_manager = OrderManager()
21
+ self.position_manager = PositionManager()
22
+ self.execution_history = []
23
+
24
+ def initialize(self) -> bool:
25
+ """Initialize execution engine."""
26
+ self.logger.info("Initializing execution engine")
27
+
28
+ if self.broker:
29
+ return self.broker.initialize()
30
+
31
+ return True
32
+
33
+ def execute_order(self, symbol: str, quantity: int, order_type: str = "market",
34
+ price: Optional[float] = None) -> str:
35
+ """Execute an order through the broker."""
36
+ try:
37
+ # Create order
38
+ order_id = self.order_manager.create_order(
39
+ symbol=symbol,
40
+ quantity=quantity,
41
+ order_type=order_type,
42
+ price=price
43
+ )
44
+
45
+ # Execute through broker
46
+ if self.broker:
47
+ broker_order_id = self.broker.place_order(
48
+ symbol=symbol,
49
+ quantity=quantity,
50
+ order_type=order_type,
51
+ price=price
52
+ )
53
+
54
+ # Update order with broker ID
55
+ order = self.order_manager.get_order(order_id)
56
+ if order:
57
+ order['broker_order_id'] = broker_order_id
58
+
59
+ self.logger.info(f"Order executed through broker: {order_id} -> {broker_order_id}")
60
+ else:
61
+ # Simulate execution
62
+ current_price = self._get_simulated_price(symbol)
63
+ self._simulate_execution(order_id, current_price)
64
+ self.logger.info(f"Order executed in simulation: {order_id}")
65
+
66
+ return order_id
67
+
68
+ except Exception as e:
69
+ raise TradingError(f"Failed to execute order: {str(e)}")
70
+
71
+ def _simulate_execution(self, order_id: str, execution_price: float):
72
+ """Simulate order execution."""
73
+ order = self.order_manager.get_order(order_id)
74
+ if not order:
75
+ return
76
+
77
+ # Mark as executed
78
+ self.order_manager.mark_executed(order_id, execution_price)
79
+
80
+ # Update position
81
+ symbol = order['symbol']
82
+ quantity = order['quantity']
83
+
84
+ if quantity > 0: # Buy
85
+ self.position_manager.add_position(symbol, quantity, execution_price)
86
+ else: # Sell
87
+ self.position_manager.reduce_position(symbol, abs(quantity), execution_price)
88
+
89
+ # Record execution
90
+ self.execution_history.append({
91
+ 'order_id': order_id,
92
+ 'symbol': symbol,
93
+ 'quantity': quantity,
94
+ 'execution_price': execution_price,
95
+ 'timestamp': pd.Timestamp.now()
96
+ })
97
+
98
+ def _get_simulated_price(self, symbol: str) -> float:
99
+ """Get simulated price for symbol."""
100
+ # Simple simulation - in real implementation this would come from market data
101
+ base_prices = {
102
+ 'AAPL': 150.0,
103
+ 'GOOGL': 2500.0,
104
+ 'MSFT': 300.0,
105
+ 'TSLA': 200.0
106
+ }
107
+ return base_prices.get(symbol, 100.0)
108
+
109
+ def get_execution_summary(self) -> Dict[str, Any]:
110
+ """Get execution summary."""
111
+ return {
112
+ 'total_orders': len(self.order_manager.get_order_history()),
113
+ 'executed_orders': len(self.order_manager.get_executed_orders()),
114
+ 'pending_orders': len(self.order_manager.get_pending_orders()),
115
+ 'total_positions': len(self.position_manager.get_all_positions()),
116
+ 'execution_history': self.execution_history
117
+ }
118
+
119
+ def cancel_order(self, order_id: str) -> bool:
120
+ """Cancel an order."""
121
+ try:
122
+ # Cancel in order manager
123
+ success = self.order_manager.cancel_order(order_id)
124
+
125
+ # Cancel with broker if available
126
+ if self.broker and success:
127
+ order = self.order_manager.get_order(order_id)
128
+ if order and 'broker_order_id' in order:
129
+ self.broker.cancel_order(order['broker_order_id'])
130
+
131
+ if success:
132
+ self.logger.info(f"Order cancelled: {order_id}")
133
+
134
+ return success
135
+
136
+ except Exception as e:
137
+ self.logger.error(f"Failed to cancel order: {str(e)}")
138
+ return False
139
+
140
+ def get_order_status(self, order_id: str) -> Dict[str, Any]:
141
+ """Get order status."""
142
+ order = self.order_manager.get_order(order_id)
143
+ if not order:
144
+ return {}
145
+
146
+ # Get status from broker if available
147
+ if self.broker and 'broker_order_id' in order:
148
+ broker_status = self.broker.get_order_status(order['broker_order_id'])
149
+ order.update(broker_status)
150
+
151
+ return order
152
+
153
+ def sync_with_broker(self) -> bool:
154
+ """Sync orders and positions with broker."""
155
+ if not self.broker:
156
+ return False
157
+
158
+ try:
159
+ # Sync positions
160
+ broker_positions = self.broker.get_positions()
161
+ # Update position manager with broker positions
162
+
163
+ # Sync order statuses
164
+ for order_id, order in self.order_manager.orders.items():
165
+ if 'broker_order_id' in order:
166
+ broker_status = self.broker.get_order_status(order['broker_order_id'])
167
+ order.update(broker_status)
168
+
169
+ self.logger.info("Synced with broker")
170
+ return True
171
+
172
+ except Exception as e:
173
+ self.logger.error(f"Failed to sync with broker: {str(e)}")
174
+ return False
175
+
176
+
@@ -0,0 +1,111 @@
1
+ """
2
+ Order management system for DeltaFQ.
3
+ """
4
+
5
+ import pandas as pd
6
+ from typing import Dict, List, Optional, Any
7
+ from datetime import datetime
8
+ from ..core.base import BaseComponent
9
+
10
+
11
+ class OrderManager(BaseComponent):
12
+ """Manage trading orders."""
13
+
14
+ def __init__(self, **kwargs):
15
+ """Initialize order manager."""
16
+ super().__init__(**kwargs)
17
+ self.orders = {}
18
+ self.order_counter = 0
19
+
20
+ def initialize(self) -> bool:
21
+ """Initialize order manager."""
22
+ self.logger.info("Initializing order manager")
23
+ return True
24
+
25
+ def create_order(self, symbol: str, quantity: int, order_type: str = "market",
26
+ price: Optional[float] = None, stop_price: Optional[float] = None) -> str:
27
+ """Create a new order."""
28
+ self.order_counter += 1
29
+ order_id = f"ORD_{self.order_counter:06d}"
30
+
31
+ order = {
32
+ 'id': order_id,
33
+ 'symbol': symbol,
34
+ 'quantity': quantity,
35
+ 'order_type': order_type,
36
+ 'price': price,
37
+ 'stop_price': stop_price,
38
+ 'status': 'pending',
39
+ 'created_at': datetime.now(),
40
+ 'updated_at': datetime.now()
41
+ }
42
+
43
+ self.orders[order_id] = order
44
+ self.logger.info(f"Order created: {order_id}")
45
+ return order_id
46
+
47
+ def get_order(self, order_id: str) -> Optional[Dict[str, Any]]:
48
+ """Get order by ID."""
49
+ return self.orders.get(order_id)
50
+
51
+ def update_order_status(self, order_id: str, status: str) -> bool:
52
+ """Update order status."""
53
+ if order_id in self.orders:
54
+ self.orders[order_id]['status'] = status
55
+ self.orders[order_id]['updated_at'] = datetime.now()
56
+ return True
57
+ return False
58
+
59
+ def mark_executed(self, order_id: str, execution_price: Optional[float] = None) -> bool:
60
+ """Mark order as executed."""
61
+ if order_id in self.orders:
62
+ self.orders[order_id]['status'] = 'executed'
63
+ self.orders[order_id]['execution_price'] = execution_price
64
+ self.orders[order_id]['executed_at'] = datetime.now()
65
+ self.orders[order_id]['updated_at'] = datetime.now()
66
+ return True
67
+ return False
68
+
69
+ def cancel_order(self, order_id: str) -> bool:
70
+ """Cancel an order."""
71
+ if order_id in self.orders and self.orders[order_id]['status'] == 'pending':
72
+ self.orders[order_id]['status'] = 'cancelled'
73
+ self.orders[order_id]['updated_at'] = datetime.now()
74
+ return True
75
+ return False
76
+
77
+ def get_orders_by_symbol(self, symbol: str) -> List[Dict[str, Any]]:
78
+ """Get all orders for a symbol."""
79
+ return [order for order in self.orders.values() if order['symbol'] == symbol]
80
+
81
+ def get_orders_by_status(self, status: str) -> List[Dict[str, Any]]:
82
+ """Get all orders with specific status."""
83
+ return [order for order in self.orders.values() if order['status'] == status]
84
+
85
+ def get_pending_orders(self) -> List[Dict[str, Any]]:
86
+ """Get all pending orders."""
87
+ return self.get_orders_by_status('pending')
88
+
89
+ def get_executed_orders(self) -> List[Dict[str, Any]]:
90
+ """Get all executed orders."""
91
+ return self.get_orders_by_status('executed')
92
+
93
+ def get_order_history(self) -> List[Dict[str, Any]]:
94
+ """Get complete order history."""
95
+ return list(self.orders.values())
96
+
97
+ def cleanup_old_orders(self, days: int = 30) -> int:
98
+ """Clean up old orders."""
99
+ cutoff_date = datetime.now() - pd.Timedelta(days=days)
100
+ old_orders = [
101
+ order_id for order_id, order in self.orders.items()
102
+ if order['created_at'] < cutoff_date and order['status'] in ['executed', 'cancelled']
103
+ ]
104
+
105
+ for order_id in old_orders:
106
+ del self.orders[order_id]
107
+
108
+ self.logger.info(f"Cleaned up {len(old_orders)} old orders")
109
+ return len(old_orders)
110
+
111
+
@@ -0,0 +1,157 @@
1
+ """
2
+ Position management for DeltaFQ.
3
+ """
4
+
5
+ from typing import Dict, Optional, Any
6
+ from datetime import datetime
7
+ from ..core.base import BaseComponent
8
+
9
+
10
+ class PositionManager(BaseComponent):
11
+ """Manage trading positions."""
12
+
13
+ def __init__(self, **kwargs):
14
+ """Initialize position manager."""
15
+ super().__init__(**kwargs)
16
+ self.positions = {}
17
+ self.position_history = []
18
+
19
+ def initialize(self) -> bool:
20
+ """Initialize position manager."""
21
+ self.logger.info("Initializing position manager")
22
+ return True
23
+
24
+ def add_position(self, symbol: str, quantity: int, price: Optional[float] = None) -> bool:
25
+ """Add to existing position or create new position."""
26
+ try:
27
+ if symbol in self.positions:
28
+ # Update existing position
29
+ current_quantity = self.positions[symbol]['quantity']
30
+ current_avg_price = self.positions[symbol]['avg_price']
31
+
32
+ new_quantity = current_quantity + quantity
33
+ if price:
34
+ new_avg_price = ((current_quantity * current_avg_price) + (quantity * price)) / new_quantity
35
+ else:
36
+ new_avg_price = current_avg_price
37
+
38
+ self.positions[symbol]['quantity'] = new_quantity
39
+ self.positions[symbol]['avg_price'] = new_avg_price
40
+ self.positions[symbol]['updated_at'] = datetime.now()
41
+ else:
42
+ # Create new position
43
+ self.positions[symbol] = {
44
+ 'symbol': symbol,
45
+ 'quantity': quantity,
46
+ 'avg_price': price or 0.0,
47
+ 'created_at': datetime.now(),
48
+ 'updated_at': datetime.now()
49
+ }
50
+
51
+ # Record in history
52
+ self.position_history.append({
53
+ 'symbol': symbol,
54
+ 'quantity': quantity,
55
+ 'price': price,
56
+ 'action': 'add',
57
+ 'timestamp': datetime.now()
58
+ })
59
+
60
+ self.logger.info(f"Position updated: {symbol} -> {self.positions[symbol]['quantity']}")
61
+ return True
62
+
63
+ except Exception as e:
64
+ self.logger.error(f"Failed to add position: {str(e)}")
65
+ return False
66
+
67
+ def reduce_position(self, symbol: str, quantity: int, price: Optional[float] = None) -> bool:
68
+ """Reduce existing position."""
69
+ try:
70
+ if symbol not in self.positions:
71
+ self.logger.warning(f"No position found for symbol: {symbol}")
72
+ return False
73
+
74
+ current_quantity = self.positions[symbol]['quantity']
75
+ if current_quantity < quantity:
76
+ self.logger.warning(f"Insufficient position: {symbol}")
77
+ return False
78
+
79
+ new_quantity = current_quantity - quantity
80
+
81
+ if new_quantity == 0:
82
+ # Close position
83
+ del self.positions[symbol]
84
+ else:
85
+ # Update position
86
+ self.positions[symbol]['quantity'] = new_quantity
87
+ self.positions[symbol]['updated_at'] = datetime.now()
88
+
89
+ # Record in history
90
+ self.position_history.append({
91
+ 'symbol': symbol,
92
+ 'quantity': -quantity,
93
+ 'price': price,
94
+ 'action': 'reduce',
95
+ 'timestamp': datetime.now()
96
+ })
97
+
98
+ self.logger.info(f"Position reduced: {symbol} -> {new_quantity}")
99
+ return True
100
+
101
+ except Exception as e:
102
+ self.logger.error(f"Failed to reduce position: {str(e)}")
103
+ return False
104
+
105
+ def get_position(self, symbol: str) -> int:
106
+ """Get current position quantity for symbol."""
107
+ return self.positions.get(symbol, {}).get('quantity', 0)
108
+
109
+ def get_all_positions(self) -> Dict[str, int]:
110
+ """Get all current positions."""
111
+ return {symbol: pos['quantity'] for symbol, pos in self.positions.items()}
112
+
113
+ def get_position_details(self, symbol: str) -> Optional[Dict[str, Any]]:
114
+ """Get detailed position information."""
115
+ return self.positions.get(symbol)
116
+
117
+ def get_all_position_details(self) -> Dict[str, Dict[str, Any]]:
118
+ """Get all position details."""
119
+ return dict(self.positions)
120
+
121
+ def can_sell(self, symbol: str, quantity: int) -> bool:
122
+ """Check if we can sell the specified quantity."""
123
+ current_position = self.get_position(symbol)
124
+ return current_position >= quantity
125
+
126
+ def get_position_value(self, symbol: str, current_price: float) -> float:
127
+ """Calculate position value at current price."""
128
+ quantity = self.get_position(symbol)
129
+ return quantity * current_price
130
+
131
+ def get_total_position_value(self, current_prices: Dict[str, float]) -> float:
132
+ """Calculate total position value."""
133
+ total_value = 0.0
134
+ for symbol, position in self.positions.items():
135
+ if symbol in current_prices:
136
+ total_value += position['quantity'] * current_prices[symbol]
137
+ return total_value
138
+
139
+ def close_position(self, symbol: str, price: Optional[float] = None) -> bool:
140
+ """Close entire position for symbol."""
141
+ if symbol not in self.positions:
142
+ return False
143
+
144
+ quantity = self.positions[symbol]['quantity']
145
+ return self.reduce_position(symbol, quantity, price)
146
+
147
+ def close_all_positions(self, current_prices: Dict[str, float]) -> Dict[str, bool]:
148
+ """Close all positions."""
149
+ results = {}
150
+ symbols = list(self.positions.keys())
151
+
152
+ for symbol in symbols:
153
+ results[symbol] = self.close_position(symbol, current_prices.get(symbol))
154
+
155
+ return results
156
+
157
+