Skip to content

Commit 5673ed5

Browse files
committed
centralized realtime order and position tracking
1 parent 35de2c5 commit 5673ed5

File tree

11 files changed

+442
-165
lines changed

11 files changed

+442
-165
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A **high-performance Python client** for the TopStepX ProjectX Gateway API, desi
99

1010
## 📊 Project Status
1111

12-
**Current Version**: v1.0.5 (Enhanced with Complete TA-Lib Overlap Indicators)
12+
**Current Version**: v1.0.11 (Enhanced with Complete TA-Lib Overlap Indicators)
1313

1414
**Production Ready Features**:
1515
- Complete futures trading API integration with connection pooling
@@ -570,7 +570,7 @@ We welcome contributions! Please follow these guidelines:
570570

571571
## 📊 Project Status & Roadmap
572572

573-
### ✅ Completed (v1.0.2 - Current)
573+
### ✅ Completed (v1.0.11 - Current)
574574
- [x] **High-Performance Architecture** - Connection pooling, caching, memory management
575575
- [x] **Core Trading API** - Complete order management with optimization
576576
- [x] **Advanced Market Data** - Real-time streams with intelligent caching
@@ -579,6 +579,7 @@ We welcome contributions! Please follow these guidelines:
579579
- [x] **Performance Monitoring** - Built-in metrics and health tracking
580580
- [x] **Production-Ready** - Enterprise-grade reliability and performance
581581

582+
582583
### 🚧 Active Development (v1.1.0 - Q1 2025)
583584
- [ ] **Machine Learning Integration** - Pattern recognition and predictive models
584585
- [ ] **Advanced Backtesting** - Historical testing with performance optimization
@@ -593,7 +594,7 @@ We welcome contributions! Please follow these guidelines:
593594

594595
## 📝 Changelog
595596

596-
### Version 1.0.5 (Latest)
597+
### Version 1.0.11 (Latest)
597598
**🎯 Complete TA-Lib Overlap Indicators**
598599
-**New Overlap Indicators (10 added)**: HT_TRENDLINE, KAMA, MA, MAMA, MAVP, MIDPRICE, SAR, SAREXT, T3, TRIMA
599600
-**Enhanced WMA**: Fixed Weighted Moving Average implementation
@@ -613,7 +614,7 @@ We welcome contributions! Please follow these guidelines:
613614
- **MA**: Generic Moving Average with selectable types
614615
- **MAVP**: Moving Average with Variable Period support
615616

616-
### Version 1.0.2-1.0.4
617+
### Version 1.0.2-1.0.11
617618
**🚀 Performance & Reliability**
618619
- ✅ Connection pooling and intelligent caching
619620
- ✅ Memory management optimizations

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
project = "project-x-py"
2525
copyright = "2025, Jeff West"
2626
author = "Jeff West"
27-
release = "1.0.2"
28-
version = "1.0.2"
27+
release = "1.0.11"
28+
version = "1.0.11"
2929

3030
# -- General configuration ---------------------------------------------------
3131

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "project-x-py"
3-
version = "1.0.10"
3+
version = "1.0.11"
44
description = "Professional Python client for TopStepX ProjectX Gateway API - futures trading, real-time data, and market analysis"
55
readme = "README.md"
66
license = { text = "MIT" }

src/project_x_py/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from typing import Any, Optional
1717

18-
__version__ = "1.0.10"
18+
__version__ = "1.0.11"
1919
__author__ = "TexasCoding"
2020

2121
# Core client classes
@@ -203,6 +203,7 @@ def quick_start() -> dict:
203203
"1. Set environment variables:",
204204
" export PROJECT_X_API_KEY='your_api_key'",
205205
" export PROJECT_X_USERNAME='your_username'",
206+
" export PROJECT_X_ACCOUNT_ID='your_account_id'",
206207
"",
207208
"2. Basic usage:",
208209
" from project_x_py import ProjectX",

src/project_x_py/client.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ def __init__(
125125
self.config = config
126126
self.api_key = api_key
127127
self.username = username
128-
self.account_name = account_name # Store account name for selection
128+
self.account_name = (
129+
account_name.upper() if account_name else None
130+
) # Store account name for selection
129131

130132
# Set up timezone and URLs from config
131133
self.timezone = pytz.timezone(config.timezone)
@@ -207,7 +209,7 @@ def from_env(
207209
username=auth_config["username"],
208210
api_key=auth_config["api_key"],
209211
config=config,
210-
account_name=account_name,
212+
account_name=account_name.upper() if account_name else None,
211213
)
212214

213215
@classmethod
@@ -232,7 +234,7 @@ def from_config_file(
232234
username=auth_config["username"],
233235
api_key=auth_config["api_key"],
234236
config=config,
235-
account_name=account_name,
237+
account_name=account_name.upper() if account_name else None,
236238
)
237239

238240
def _create_session(self) -> requests.Session:
@@ -471,7 +473,7 @@ def get_account_info(self) -> Account | None:
471473
# If account_name is provided, find the specific account by name
472474
if self.account_name:
473475
for account in accounts:
474-
if account.get("name") == self.account_name:
476+
if account.get("name").upper() == self.account_name.upper():
475477
self.account_info = Account(**account)
476478
return self.account_info
477479
self.logger.warning(

src/project_x_py/indicators/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@
132132
)
133133

134134
# Version info
135-
__version__ = "1.0.10"
135+
__version__ = "1.0.11"
136136
__author__ = "TexasCoding"
137137

138138

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Lock Coordinator for Thread-Safe Component Interactions
4+
5+
This module provides coordination between different components (OrderManager,
6+
PositionManager, RealtimeClient) to prevent race conditions and ensure
7+
consistent data access patterns.
8+
"""
9+
10+
import threading
11+
from collections.abc import Generator
12+
from contextlib import contextmanager
13+
14+
15+
class LockCoordinator:
16+
"""
17+
Coordinates locks between different components to prevent deadlocks and race conditions.
18+
19+
This class ensures that when multiple components need to access shared data,
20+
they do so in a consistent order to prevent deadlocks.
21+
"""
22+
23+
def __init__(self):
24+
"""Initialize the lock coordinator."""
25+
# Master lock for coordinating component access
26+
self._master_lock = threading.RLock()
27+
28+
# Component-specific locks in a consistent order to prevent deadlocks
29+
self._realtime_lock = threading.RLock()
30+
self._order_lock = threading.RLock()
31+
self._position_lock = threading.RLock()
32+
33+
# Lock hierarchy to prevent deadlocks (always acquire in this order)
34+
self._lock_hierarchy = [
35+
self._realtime_lock, # 1. Realtime client (data source)
36+
self._order_lock, # 2. Order manager
37+
self._position_lock, # 3. Position manager
38+
]
39+
40+
@property
41+
def realtime_lock(self) -> threading.RLock:
42+
"""Get the realtime client lock."""
43+
return self._realtime_lock
44+
45+
@property
46+
def order_lock(self) -> threading.RLock:
47+
"""Get the order manager lock."""
48+
return self._order_lock
49+
50+
@property
51+
def position_lock(self) -> threading.RLock:
52+
"""Get the position manager lock."""
53+
return self._position_lock
54+
55+
@contextmanager
56+
def coordinated_access(self, *components: str) -> Generator[None, None, None]:
57+
"""
58+
Acquire locks for multiple components in a safe order.
59+
60+
Args:
61+
*components: Component names ('realtime', 'order', 'position')
62+
63+
Example:
64+
>>> with coordinator.coordinated_access("realtime", "order"):
65+
... # Access data from both components safely
66+
... pass
67+
"""
68+
# Map component names to locks
69+
component_locks = {
70+
"realtime": self._realtime_lock,
71+
"order": self._order_lock,
72+
"position": self._position_lock,
73+
}
74+
75+
# Get locks in hierarchy order to prevent deadlocks
76+
requested_locks = []
77+
for lock in self._lock_hierarchy:
78+
for component in components:
79+
if component_locks.get(component) == lock:
80+
requested_locks.append(lock)
81+
break
82+
83+
# Acquire locks in order
84+
acquired_locks = []
85+
try:
86+
for lock in requested_locks:
87+
lock.acquire()
88+
acquired_locks.append(lock)
89+
yield
90+
finally:
91+
# Release locks in reverse order
92+
for lock in reversed(acquired_locks):
93+
lock.release()
94+
95+
@contextmanager
96+
def all_components_locked(self) -> Generator[None, None, None]:
97+
"""
98+
Acquire all component locks for major operations.
99+
100+
Use this for operations that need to modify data across multiple components.
101+
"""
102+
with self.coordinated_access("realtime", "order", "position"):
103+
yield
104+
105+
106+
# Global lock coordinator instance (singleton pattern)
107+
_global_coordinator: LockCoordinator | None = None
108+
_coordinator_lock = threading.Lock()
109+
110+
111+
def get_lock_coordinator() -> LockCoordinator:
112+
"""
113+
Get the global lock coordinator instance.
114+
115+
Returns:
116+
LockCoordinator: The singleton coordinator instance
117+
"""
118+
global _global_coordinator
119+
120+
if _global_coordinator is None:
121+
with _coordinator_lock:
122+
if _global_coordinator is None:
123+
_global_coordinator = LockCoordinator()
124+
125+
return _global_coordinator

0 commit comments

Comments
 (0)