3838from enum import Enum
3939from pathlib import Path
4040from types import TracebackType
41- from typing import Any
41+ from typing import Any , cast
4242
4343import orjson
4444import yaml
6060 OrderManagerConfig ,
6161 PositionManagerConfig ,
6262)
63+ from project_x_py .types .protocols import ProjectXClientProtocol
6364from project_x_py .types .stats_types import ComponentStats , TradingSuiteStats
6465from project_x_py .utils import ProjectXLogger
6566
@@ -87,16 +88,33 @@ def __init__(
8788 initial_days : int = 5 ,
8889 auto_connect : bool = True ,
8990 timezone : str = "America/Chicago" ,
91+ order_manager_config : OrderManagerConfig | None = None ,
92+ position_manager_config : PositionManagerConfig | None = None ,
93+ data_manager_config : DataManagerConfig | None = None ,
94+ orderbook_config : OrderbookConfig | None = None ,
95+ risk_config : RiskConfig | None = None ,
9096 ):
9197 self .instrument = instrument
9298 self .timeframes = timeframes or ["5min" ]
9399 self .features = features or []
94100 self .initial_days = initial_days
95101 self .auto_connect = auto_connect
96102 self .timezone = timezone
103+ self .order_manager_config = order_manager_config
104+ self .position_manager_config = position_manager_config
105+ self .data_manager_config = data_manager_config
106+ self .orderbook_config = orderbook_config
107+ self .risk_config = risk_config
97108
98109 def get_order_manager_config (self ) -> OrderManagerConfig :
99- """Get configuration for OrderManager."""
110+ """
111+ Get configuration for OrderManager.
112+
113+ Returns:
114+ OrderManagerConfig: The configuration for the OrderManager.
115+ """
116+ if self .order_manager_config :
117+ return self .order_manager_config
100118 return {
101119 "enable_bracket_orders" : Features .RISK_MANAGER in self .features ,
102120 "enable_trailing_stops" : True ,
@@ -105,7 +123,14 @@ def get_order_manager_config(self) -> OrderManagerConfig:
105123 }
106124
107125 def get_position_manager_config (self ) -> PositionManagerConfig :
108- """Get configuration for PositionManager."""
126+ """
127+ Get configuration for PositionManager.
128+
129+ Returns:
130+ PositionManagerConfig: The configuration for the PositionManager.
131+ """
132+ if self .position_manager_config :
133+ return self .position_manager_config
109134 return {
110135 "enable_risk_monitoring" : Features .RISK_MANAGER in self .features ,
111136 "enable_correlation_analysis" : Features .PERFORMANCE_ANALYTICS
@@ -114,7 +139,14 @@ def get_position_manager_config(self) -> PositionManagerConfig:
114139 }
115140
116141 def get_data_manager_config (self ) -> DataManagerConfig :
117- """Get configuration for RealtimeDataManager."""
142+ """
143+ Get configuration for RealtimeDataManager.
144+
145+ Returns:
146+ DataManagerConfig: The configuration for the RealtimeDataManager.
147+ """
148+ if self .data_manager_config :
149+ return self .data_manager_config
118150 return {
119151 "max_bars_per_timeframe" : 1000 ,
120152 "enable_tick_data" : True ,
@@ -124,7 +156,14 @@ def get_data_manager_config(self) -> DataManagerConfig:
124156 }
125157
126158 def get_orderbook_config (self ) -> OrderbookConfig :
127- """Get configuration for OrderBook."""
159+ """
160+ Get configuration for OrderBook.
161+
162+ Returns:
163+ OrderbookConfig: The configuration for the OrderBook.
164+ """
165+ if self .orderbook_config :
166+ return self .orderbook_config
128167 return {
129168 "max_depth_levels" : 100 ,
130169 "max_trade_history" : 1000 ,
@@ -133,7 +172,14 @@ def get_orderbook_config(self) -> OrderbookConfig:
133172 }
134173
135174 def get_risk_config (self ) -> RiskConfig :
136- """Get configuration for RiskManager."""
175+ """
176+ Get configuration for RiskManager.
177+
178+ Returns:
179+ RiskConfig: The configuration for the RiskManager.
180+ """
181+ if self .risk_config :
182+ return self .risk_config
137183 return RiskConfig (
138184 max_risk_per_trade = 0.01 , # 1% per trade
139185 max_daily_loss = 0.03 , # 3% daily loss
@@ -208,30 +254,25 @@ def __init__(
208254 self .journal = None # TODO: Future enhancement
209255 self .analytics = None # TODO: Future enhancement
210256
211- # Initialize risk manager first if enabled (needed by PositionManager)
212- if Features .RISK_MANAGER in config .features :
213- # Create RiskManager without position_manager first
214- self .risk_manager = RiskManager (
215- project_x = client ,
216- order_manager = self .orders ,
217- event_bus = self .events ,
218- position_manager = None , # Will be set after PositionManager is created
219- config = config .get_risk_config (),
220- )
221-
222- # Now create PositionManager with risk_manager
257+ # Create PositionManager first
223258 self .positions = PositionManager (
224259 client ,
225260 event_bus = self .events ,
226- risk_manager = self . risk_manager ,
227- data_manager = self .data , # type: ignore
261+ risk_manager = None , # Will be set later
262+ data_manager = self .data ,
228263 config = config .get_position_manager_config (),
229264 )
230265
231- # Update RiskManager with position_manager reference if it exists
232- if self .risk_manager :
233- self .risk_manager .position_manager = self .positions
234- self .risk_manager .positions = self .positions # Also set positions attribute
266+ # Initialize risk manager if enabled and inject dependencies
267+ if Features .RISK_MANAGER in config .features :
268+ self .risk_manager = RiskManager (
269+ project_x = cast (ProjectXClientProtocol , client ),
270+ order_manager = self .orders ,
271+ event_bus = self .events ,
272+ position_manager = self .positions ,
273+ config = config .get_risk_config (),
274+ )
275+ self .positions .risk_manager = self .risk_manager
235276
236277 # State tracking
237278 self ._connected = False
@@ -791,53 +832,64 @@ def get_stats(self) -> TradingSuiteStats:
791832 # Build component stats
792833 components : dict [str , ComponentStats ] = {}
793834 if self .orders :
835+ last_activity_obj = self .orders .stats .get ("last_order_time" )
794836 components ["order_manager" ] = ComponentStats (
795837 name = "OrderManager" ,
796838 status = "connected" if self .orders else "disconnected" ,
797839 uptime_seconds = uptime_seconds ,
798- last_activity = None ,
799- error_count = 0 ,
800- memory_usage_mb = 0.0 ,
840+ last_activity = last_activity_obj .isoformat ()
841+ if last_activity_obj
842+ else None ,
843+ error_count = 0 , # TODO: Implement error tracking in OrderManager
844+ memory_usage_mb = 0.0 , # TODO: Implement memory tracking in OrderManager
801845 )
802846
803847 if self .positions :
848+ last_activity_obj = self .positions .stats .get ("last_position_update" )
804849 components ["position_manager" ] = ComponentStats (
805850 name = "PositionManager" ,
806851 status = "connected" if self .positions else "disconnected" ,
807852 uptime_seconds = uptime_seconds ,
808- last_activity = None ,
809- error_count = 0 ,
810- memory_usage_mb = 0.0 ,
853+ last_activity = last_activity_obj .isoformat ()
854+ if last_activity_obj
855+ else None ,
856+ error_count = 0 , # TODO: Implement error tracking in PositionManager
857+ memory_usage_mb = 0.0 , # TODO: Implement memory tracking in PositionManager
811858 )
812859
813860 if self .data :
861+ last_activity_obj = self .data .memory_stats .get ("last_update" )
814862 components ["data_manager" ] = ComponentStats (
815863 name = "RealtimeDataManager" ,
816864 status = "connected" if self .data else "disconnected" ,
817865 uptime_seconds = uptime_seconds ,
818- last_activity = None ,
819- error_count = 0 ,
820- memory_usage_mb = 0.0 ,
866+ last_activity = last_activity_obj .isoformat ()
867+ if last_activity_obj
868+ else None ,
869+ error_count = self .data .memory_stats .get ("data_validation_errors" , 0 ),
870+ memory_usage_mb = self .data .memory_stats .get ("memory_usage_mb" , 0.0 ),
821871 )
822872
823873 if self .orderbook :
824874 components ["orderbook" ] = ComponentStats (
825875 name = "OrderBook" ,
826876 status = "connected" if self .orderbook else "disconnected" ,
827877 uptime_seconds = uptime_seconds ,
828- last_activity = None ,
829- error_count = 0 ,
830- memory_usage_mb = 0.0 ,
878+ last_activity = self .orderbook .last_orderbook_update .isoformat ()
879+ if self .orderbook .last_orderbook_update
880+ else None ,
881+ error_count = 0 , # TODO: Implement error tracking in OrderBook
882+ memory_usage_mb = 0.0 , # TODO: Implement memory tracking in OrderBook
831883 )
832884
833885 if self .risk_manager :
834886 components ["risk_manager" ] = ComponentStats (
835887 name = "RiskManager" ,
836888 status = "active" if self .risk_manager else "inactive" ,
837889 uptime_seconds = uptime_seconds ,
838- last_activity = None ,
839- error_count = 0 ,
840- memory_usage_mb = 0.0 ,
890+ last_activity = None , # TODO: Implement activity tracking in RiskManager
891+ error_count = 0 , # TODO: Implement error tracking in RiskManager
892+ memory_usage_mb = 0.0 , # TODO: Implement memory tracking in RiskManager
841893 )
842894
843895 return {
0 commit comments