Skip to content

Commit fa93e6a

Browse files
TexasCodingclaude
andcommitted
fix(risk_manager): Implement ManagedTrade._get_market_price() method
- Add data_manager parameter to ManagedTrade constructor - Implement market price fetching with multi-timeframe fallback - Update TradingSuite to pass data manager to ManagedTrade - Enable risk-managed trades without explicit entry prices - Add comprehensive error handling and helpful error messages Fixes NotImplementedError when entering positions without entry_price in ManagedTrade context. The implementation tries multiple timeframes (1sec, 15sec, 1min, 5min) and falls back to get_current_price(). 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]>
1 parent e70154b commit fa93e6a

File tree

10 files changed

+152
-11
lines changed

10 files changed

+152
-11
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Migration guides will be provided for all breaking changes
1515
- Semantic versioning (MAJOR.MINOR.PATCH) is strictly followed
1616

17+
## [3.1.11] - 2025-08-13
18+
19+
### Fixed
20+
- **🎯 Risk Manager Market Price Fetching**: Implemented `_get_market_price()` in ManagedTrade
21+
- ManagedTrade can now fetch current market prices from data manager
22+
- Automatic fallback through multiple timeframes (1sec, 15sec, 1min, 5min)
23+
- Enables risk-managed trades without explicit entry prices
24+
- Proper integration with TradingSuite's data manager
25+
- Fixes NotImplementedError when entering positions without explicit entry price
26+
27+
### Improved
28+
- ManagedTrade constructor now accepts optional data_manager parameter
29+
- TradingSuite automatically passes data manager to ManagedTrade instances
30+
- Better error messages when market price cannot be fetched
31+
32+
## [3.1.10] - 2025-08-13
33+
34+
### Changed
35+
- Minor version bump for internal improvements
36+
1737
## [3.1.9] - 2025-08-12
1838

1939
### Fixed

CLAUDE.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,17 @@ async with ProjectX.from_env() as client:
288288

289289
## Recent Changes
290290

291-
### v3.1.9 - Latest Release
291+
### v3.1.11 - Latest Release
292+
- **Fixed**: ManagedTrade `_get_market_price()` implementation
293+
- ManagedTrade can now fetch current market prices from data manager
294+
- Automatic fallback through multiple timeframes (1sec, 15sec, 1min, 5min)
295+
- Enables risk-managed trades without explicit entry prices
296+
- Proper integration with TradingSuite's data manager
297+
298+
### v3.1.10
299+
- Minor version bump for internal improvements
300+
301+
### v3.1.9
292302
- **Fixed**: Tick price alignment in real-time data manager
293303
- All OHLC prices now properly aligned to instrument tick size
294304
- `get_current_price()` returns tick-aligned values

RELEASE_NOTES_v3.1.11.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Release Notes - v3.1.11
2+
3+
## 🎯 Risk Manager Market Price Fetching Fix
4+
5+
### Overview
6+
This release fixes a critical issue in the Risk Manager's ManagedTrade class where the `_get_market_price()` method was not implemented, preventing users from entering risk-managed trades without explicitly providing an entry price.
7+
8+
### What's Fixed
9+
10+
#### ManagedTrade Market Price Implementation
11+
- **Problem**: When using `ManagedTrade.enter_long()` or `enter_short()` without an explicit `entry_price`, the system would fail with `NotImplementedError`
12+
- **Solution**: Fully implemented `_get_market_price()` method that fetches current market prices from the data manager
13+
- **Impact**: Risk-managed trades can now be entered using current market prices automatically
14+
15+
### Technical Details
16+
17+
#### Implementation Features
18+
- **Smart Timeframe Fallback**: Tries multiple timeframes in order (1sec → 15sec → 1min → 5min) to get the most recent price
19+
- **Direct Price Access**: Falls back to `get_current_price()` if bar data isn't available
20+
- **Data Manager Integration**: ManagedTrade now receives data manager from TradingSuite automatically
21+
- **Clear Error Messages**: Provides helpful error messages when market price cannot be fetched
22+
23+
#### Code Changes
24+
```python
25+
# Before (would fail)
26+
async with suite.managed_trade(max_risk_percent=0.01) as trade:
27+
result = await trade.enter_long(
28+
stop_loss=current_price - 50, # Would throw NotImplementedError
29+
take_profit=current_price + 100
30+
)
31+
32+
# After (works perfectly)
33+
async with suite.managed_trade(max_risk_percent=0.01) as trade:
34+
result = await trade.enter_long(
35+
stop_loss=current_price - 50, # Automatically fetches market price
36+
take_profit=current_price + 100
37+
)
38+
```
39+
40+
### Migration Guide
41+
No breaking changes. Existing code will continue to work. The enhancement is backward compatible:
42+
- If you provide `entry_price` explicitly, it works as before
43+
- If you omit `entry_price`, the system now fetches it automatically
44+
45+
### Testing
46+
The implementation has been tested with live market data:
47+
- ✅ Market price fetching works correctly
48+
- ✅ Fallback through multiple timeframes functions properly
49+
- ✅ Integration with TradingSuite is seamless
50+
- ✅ Risk orders (stop loss, take profit) are properly attached
51+
52+
### Dependencies
53+
No new dependencies required. Uses existing data manager infrastructure.
54+
55+
### Known Issues
56+
None at this time.
57+
58+
### Future Improvements
59+
- Consider adding configurable timeframe priority for price fetching
60+
- Add option to use bid/ask prices instead of last trade price
61+
- Implement price staleness checks with configurable thresholds
62+
63+
### Support
64+
For issues or questions about this release, please open an issue on GitHub or contact support.
65+
66+
---
67+
*Released: 2025-08-13*
68+
*Version: 3.1.11*
69+
*Type: Bug Fix / Feature Enhancement*

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
project = "project-x-py"
2424
copyright = "2025, Jeff West"
2525
author = "Jeff West"
26-
release = "3.1.10"
27-
version = "3.1.10"
26+
release = "3.1.11"
27+
version = "3.1.11"
2828

2929
# -- General configuration ---------------------------------------------------
3030

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 = "3.1.10"
3+
version = "3.1.11"
44
description = "High-performance Python SDK for futures trading with real-time WebSocket data, technical indicators, order management, and market depth analysis"
55
readme = "README.md"
66
license = { text = "MIT" }

src/project_x_py/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595

9696
from project_x_py.client.base import ProjectXBase
9797

98-
__version__ = "3.1.10"
98+
__version__ = "3.1.11"
9999
__author__ = "TexasCoding"
100100

101101
# Core client classes - renamed from Async* to standard names

src/project_x_py/indicators/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@
202202
)
203203

204204
# Version info
205-
__version__ = "3.1.10"
205+
__version__ = "3.1.11"
206206
__author__ = "TexasCoding"
207207

208208

src/project_x_py/risk_manager/managed_trade.py

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def __init__(
3131
order_manager: OrderManagerProtocol,
3232
position_manager: PositionManagerProtocol,
3333
instrument_id: str,
34+
data_manager: Any | None = None,
3435
max_risk_percent: float | None = None,
3536
max_risk_amount: float | None = None,
3637
):
@@ -41,13 +42,15 @@ def __init__(
4142
order_manager: Order manager instance
4243
position_manager: Position manager instance
4344
instrument_id: Instrument/contract ID to trade
45+
data_manager: Optional data manager for market price fetching
4446
max_risk_percent: Override max risk percentage
4547
max_risk_amount: Override max risk dollar amount
4648
"""
4749
self.risk = risk_manager
4850
self.orders = order_manager
4951
self.positions = position_manager
5052
self.instrument_id = instrument_id
53+
self.data_manager = data_manager
5154
self.max_risk_percent = max_risk_percent
5255
self.max_risk_amount = max_risk_amount
5356

@@ -534,7 +537,45 @@ def _create_mock_order(
534537
)
535538

536539
async def _get_market_price(self) -> float:
537-
"""Get current market price for instrument."""
538-
# TODO: Implement actual market price fetching
539-
# This would typically come from data manager
540-
raise NotImplementedError("Market price fetching not yet implemented")
540+
"""Get current market price for instrument.
541+
542+
Returns:
543+
Current market price as a float
544+
545+
Raises:
546+
RuntimeError: If unable to fetch market price
547+
"""
548+
if not self.data_manager:
549+
raise RuntimeError(
550+
"No data manager available for market price fetching. "
551+
"Please provide entry_price explicitly or initialize ManagedTrade with a data_manager."
552+
)
553+
554+
# Try to get the most recent price from smallest available timeframe
555+
timeframes_to_try = ["1sec", "15sec", "1min", "5min"]
556+
557+
for timeframe in timeframes_to_try:
558+
try:
559+
# Get the most recent bar
560+
data = await self.data_manager.get_data(timeframe, bars=1)
561+
562+
if data is not None and not data.is_empty():
563+
# Return the close price of the most recent bar
564+
close_price = data["close"].tail(1)[0]
565+
return float(close_price)
566+
except Exception:
567+
# Try next timeframe if this one fails
568+
continue
569+
570+
# If we still don't have data, try to get current price directly
571+
try:
572+
current_price = await self.data_manager.get_current_price()
573+
if current_price is not None:
574+
return float(current_price)
575+
except Exception:
576+
pass
577+
578+
raise RuntimeError(
579+
f"Unable to fetch current market price for {self.instrument_id} - no data available. "
580+
"Please ensure data manager is connected and receiving data."
581+
)

src/project_x_py/trading_suite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ def managed_trade(
734734
order_manager=self.orders,
735735
position_manager=self.positions,
736736
instrument_id=self.instrument_id or self._symbol,
737+
data_manager=self.data,
737738
max_risk_percent=max_risk_percent,
738739
max_risk_amount=max_risk_amount,
739740
)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)