Skip to content

Commit a8af4e9

Browse files
authored
Merge pull request #7 from TexasCoding:test_kilo
Test_kilo
2 parents 9babaf2 + 36600fc commit a8af4e9

38 files changed

+1662
-309
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
__pycache__/
33
*.py[cod]
44
*$py.class
5-
5+
.grok/settings.json
66
# C extensions
77
*.so
88

.grok/GROK.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# GROK.md
2+
3+
This file provides guidance to Grok CLI (x.ai/grok) when assisting with file editing, coding tasks, and system operations in this repository.
4+
5+
## Project Overview
6+
This is a Python SDK/client library for the ProjectX Trading Platform Gateway API. It enables developers to build trading strategies with access to real-time market data, order management, and analysis using Polars for high-performance data processing.
7+
8+
**Note**: Focus on toolkit development, not on creating trading strategies.
9+
10+
## Tool Usage Guidelines
11+
As Grok CLI, you have access to tools like view_file, create_file, str_replace_editor, bash, search, and todo lists. Use them efficiently for tasks.
12+
13+
- **ALWAYS** create a todo list for complex tasks.
14+
- **NEVER** overwrite existing files with create_file; use str_replace_editor.
15+
- **ALWAYS** view files before editing.
16+
- For searches, use the search tool or bash commands like grep.
17+
18+
## Development Commands
19+
Use bash tool to execute these:
20+
21+
### Package Management (UV)
22+
uv add [package] # Add a dependency
23+
uv add --dev [package] # Add a development dependency
24+
uv sync # Install/sync dependencies
25+
uv run [command] # Run command in virtual environment
26+
27+
### Testing
28+
uv run pytest # Run all tests
29+
uv run pytest tests/test_client.py # Run specific test file
30+
31+
### Code Quality
32+
uv run ruff check . # Lint code
33+
uv run ruff check . --fix # Auto-fix linting issues
34+
uv run ruff format . # Format code
35+
uv run mypy src/ # Type checking
36+
37+
## Project Architecture
38+
Refer to CLAUDE.md for details, but when editing:
39+
- Use dependency injection in clients and managers.
40+
- Handle real-time data with WebSockets.
41+
- Ensure thread safety with locks.
42+
43+
## Coding Rules for Edits
44+
When using str_replace_editor:
45+
- **ALWAYS** use modern Python 3.10+ features.
46+
- **PREFER** Polars over Pandas.
47+
- **ALWAYS** add type hints using | for unions.
48+
- **HANDLE** errors with custom exceptions.
49+
50+
## Performance Considerations
51+
- Implement memory management in edits (e.g., sliding windows).
52+
- Optimize DataFrame operations with chaining and lazy evaluation.
53+
54+
## Integration with ProjectX API
55+
- Use configurable endpoints.
56+
- Validate payloads strictly.
57+
- Map enums correctly.
58+
59+
For any updates, ensure consistency with .cursorrules and CLAUDE.md.
60+

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ All notable changes to the ProjectX Python client will be documented in this fil
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.2] - 2025-01-28
9+
10+
### Enhanced
11+
- **🚀 OrderBook Performance Optimization**: Significant performance improvements for cluster detection
12+
- **Dynamic Tick Size Detection**: OrderBook now uses real instrument metadata from ProjectX client
13+
- **Cached Instrument Data**: Tick size fetched once during initialization, eliminating repeated API calls
14+
- **Improved Cluster Analysis**: More accurate price tolerance based on actual instrument tick sizes
15+
- **Backward Compatibility**: Maintains fallback to hardcoded values when client unavailable
16+
- **🔧 Factory Function Updates**: Enhanced `create_orderbook()` to accept ProjectX client reference
17+
- **Better Integration**: OrderBook now integrates seamlessly with ProjectX client architecture
18+
- **Dependency Injection**: Proper client reference passing for instrument metadata access
19+
20+
### Fixed
21+
- **⚡ API Call Reduction**: Eliminated redundant `get_instrument()` calls during cluster detection
22+
- **🎯 Price Tolerance Accuracy**: Fixed hardcoded tick size assumptions with dynamic instrument lookup
23+
- **📊 Consistent Analysis**: OrderBook methods now use consistent, accurate tick size throughout lifecycle
24+
825
## [1.1.0] - 2025-01-27
926

1027
### Added

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ This Python SDK acts as a bridge between your trading strategies and the Project
2222

2323
## 📊 SDK Status
2424

25-
**Current Version**: v1.1.1 (Documentation Accuracy & Enhanced Project Structure)
25+
**Current Version**: v1.1.2 (Documentation Accuracy & Enhanced Project Structure)
2626

2727
**Production Ready SDK Components**:
2828
- Complete ProjectX Gateway API integration with connection pooling
2929
- Historical and real-time market data APIs with intelligent caching
3030
- 55+ technical indicators with computation caching (Full TA-Lib compatibility)
31-
- Institutional-grade orderbook analysis tools with memory management
31+
- Institutional-grade orderbook analysis tools with memory management and dynamic tick size detection
3232
- Portfolio and risk management APIs
3333
- **NEW**: 50-70% performance improvements through optimization
3434
- **NEW**: 60% memory usage reduction with sliding windows
@@ -296,10 +296,11 @@ for order in orders:
296296

297297
### Level 2 Market Depth Analysis
298298
```python
299-
from project_x_py import create_orderbook
299+
from project_x_py import create_orderbook, ProjectX
300300

301-
# Create orderbook with memory management
302-
orderbook = create_orderbook("MGC")
301+
# Create orderbook with dynamic tick size detection
302+
client = ProjectX.from_env()
303+
orderbook = create_orderbook("MGC", project_x=client) # Uses real instrument metadata
303304

304305
# Process market depth data (automatically from WebSocket)
305306
depth_snapshot = orderbook.get_orderbook_snapshot()
@@ -605,7 +606,7 @@ We welcome contributions! Please follow these guidelines:
605606

606607
## 📝 Changelog
607608

608-
### Version 1.1.1 (Latest)
609+
### Version 1.1.2 (Latest)
609610
**📊 Documentation Accuracy & Enhanced Project Structure**
610611
-**Documentation Alignment**: Updated all documentation to match actual codebase
611612
-**Version Consistency**: Corrected version references throughout project

docs/api/orderbook.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ Quick Start
2121

2222
.. code-block:: python
2323
24-
from project_x_py import ProjectX, OrderBook
24+
from project_x_py import ProjectX, create_orderbook
2525
26-
# Create client and orderbook
26+
# Create client and orderbook with dynamic tick size detection
2727
client = ProjectX.from_env()
28-
orderbook = OrderBook("MGC")
28+
orderbook = create_orderbook("MGC", project_x=client) # Uses real instrument metadata
2929
3030
# Get real-time market depth (requires real-time data subscription)
3131
snapshot = orderbook.get_orderbook_snapshot(levels=10)

docs/conf.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# For the full list of built-in configuration values, see the documentation:
44
# https://www.sphinx-doc.org/en/master/usage/configuration.html
55

6-
import os
76
import sys
87
from pathlib import Path
98

@@ -24,8 +23,8 @@
2423
project = "project-x-py"
2524
copyright = "2025, Jeff West"
2625
author = "Jeff West"
27-
release = "1.1.1"
28-
version = "1.1.1"
26+
release = "1.1.2"
27+
version = "1.1.2"
2928

3029
# -- General configuration ---------------------------------------------------
3130

@@ -199,7 +198,7 @@
199198

200199
# SEO
201200
html_title = f"ProjectX Python SDK {version} documentation"
202-
html_short_title = f"ProjectX Python SDK docs"
201+
html_short_title = "ProjectX Python SDK docs"
203202

204203
# GitHub integration
205204
html_context = {

examples/02_order_management.py

Lines changed: 95 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,19 @@ def show_order_status(order_manager, order_id: int, description: str):
4949
"""Show detailed order status information."""
5050
print(f"\n📋 {description} Status:")
5151

52-
# Check if order is tracked
53-
order_data = order_manager.get_tracked_order_status(order_id)
52+
# Check if order is tracked in real-time cache (with built-in wait)
53+
order_data = order_manager.get_tracked_order_status(
54+
str(order_id), wait_for_cache=True
55+
)
56+
5457
if order_data:
5558
status_map = {1: "Open", 2: "Filled", 3: "Cancelled", 4: "Partially Filled"}
5659
status = status_map.get(
5760
order_data.get("status", 0), f"Unknown ({order_data.get('status')})"
5861
)
5962

6063
print(f" Order ID: {order_id}")
61-
print(f" Status: {status}")
64+
print(f" Status: {status} (from real-time cache)")
6265
print(f" Side: {'BUY' if order_data.get('side') == 0 else 'SELL'}")
6366
print(f" Size: {order_data.get('size', 0)}")
6467
print(f" Fill Volume: {order_data.get('fillVolume', 0)}")
@@ -70,7 +73,18 @@ def show_order_status(order_manager, order_id: int, description: str):
7073
if order_data.get("filledPrice"):
7174
print(f" Filled Price: ${order_data['filledPrice']:.2f}")
7275
else:
73-
print(f" Order {order_id} not found in tracking cache")
76+
# Fall back to API check for status
77+
print(f" Order {order_id} not in real-time cache, checking API...")
78+
api_order = order_manager.get_order_by_id(order_id)
79+
if api_order:
80+
status_map = {1: "Open", 2: "Filled", 3: "Cancelled", 4: "Partially Filled"}
81+
status = status_map.get(api_order.status, f"Unknown ({api_order.status})")
82+
print(f" Status: {status} (from API)")
83+
print(f" Side: {'BUY' if api_order.side == 0 else 'SELL'}")
84+
print(f" Size: {api_order.size}")
85+
print(f" Fill Volume: {api_order.fillVolume}")
86+
else:
87+
print(f" Order {order_id} not found in API either")
7488

7589
# Check if filled
7690
is_filled = order_manager.is_order_filled(order_id)
@@ -327,6 +341,7 @@ def main():
327341
for i in range(6): # 30 seconds, check every 5 seconds
328342
print(f"\n⏰ Check {i + 1}/6...")
329343

344+
# Check for filled orders and positions
330345
filled_orders = []
331346
for order_id in demo_orders:
332347
if order_manager.is_order_filled(order_id):
@@ -341,14 +356,41 @@ def main():
341356
else:
342357
print("📋 No orders filled yet")
343358

359+
# Check current positions (to detect fills that weren't caught)
360+
current_positions = client.search_open_positions()
361+
if current_positions:
362+
print(f"📊 Open positions: {len(current_positions)}")
363+
for pos in current_positions:
364+
side = "LONG" if pos.type == 1 else "SHORT"
365+
print(
366+
f" {pos.contractId}: {side} {pos.size} @ ${pos.averagePrice:.2f}"
367+
)
368+
344369
# Show current open orders
345370
open_orders = order_manager.search_open_orders(
346371
contract_id=contract_id
347372
)
348373
print(f"📊 Open orders: {len(open_orders)}")
374+
if open_orders:
375+
for order in open_orders:
376+
side = "BUY" if order.side == 0 else "SELL"
377+
order_type = {1: "LIMIT", 2: "MARKET", 4: "STOP"}.get(
378+
order.type, f"TYPE_{order.type}"
379+
)
380+
status = {1: "OPEN", 2: "FILLED", 3: "CANCELLED"}.get(
381+
order.status, f"STATUS_{order.status}"
382+
)
383+
price = ""
384+
if hasattr(order, "limitPrice") and order.limitPrice:
385+
price = f" @ ${order.limitPrice:.2f}"
386+
elif hasattr(order, "stopPrice") and order.stopPrice:
387+
price = f" @ ${order.stopPrice:.2f}"
388+
print(
389+
f" Order #{order.id}: {side} {order.size} {order_type}{price} - {status}"
390+
)
349391

350392
if i < 5: # Don't sleep on last iteration
351-
time.sleep(5)
393+
time.sleep(20)
352394

353395
# Show final order statistics
354396
print("\n" + "=" * 50)
@@ -365,31 +407,61 @@ def main():
365407
print(f" Real-time Enabled: {stats['realtime_enabled']}")
366408

367409
finally:
368-
# Cleanup: Cancel remaining demo orders
369-
if demo_orders:
370-
print("\n" + "=" * 50)
371-
print("🧹 CLEANUP - CANCELLING ORDERS")
372-
print("=" * 50)
410+
# Enhanced cleanup: Cancel ALL orders and close ALL positions
411+
print("\n" + "=" * 50)
412+
print("🧹 ENHANCED CLEANUP - ORDERS & POSITIONS")
413+
print("=" * 50)
373414

374-
print("Cancelling all demo orders for safety...")
415+
try:
416+
# First, get ALL open orders (not just demo orders)
417+
all_orders = order_manager.search_open_orders()
418+
print(f"Found {len(all_orders)} total open orders")
419+
420+
# Cancel all orders
375421
cancelled_count = 0
422+
for order in all_orders:
423+
try:
424+
if order_manager.cancel_order(order.id):
425+
print(f"✅ Cancelled order #{order.id}")
426+
cancelled_count += 1
427+
else:
428+
print(f"❌ Failed to cancel order #{order.id}")
429+
except Exception as e:
430+
print(f"❌ Error cancelling order #{order.id}: {e}")
431+
432+
# Check for positions and close them
433+
positions = client.search_open_positions()
434+
print(f"Found {len(positions)} open positions")
376435

377-
for order_id in demo_orders:
436+
closed_count = 0
437+
for position in positions:
378438
try:
379-
# Check if order is still open before trying to cancel
380-
order_data = order_manager.get_tracked_order_status(order_id)
381-
if order_data and order_data.get("status") == 1: # Open
382-
if order_manager.cancel_order(order_id):
383-
print(f"✅ Cancelled order #{order_id}")
384-
cancelled_count += 1
385-
else:
386-
print(f"❌ Failed to cancel order #{order_id}")
439+
side_text = "LONG" if position.type == 1 else "SHORT"
440+
print(
441+
f"Closing {side_text} position: {position.contractId} ({position.size} contracts)"
442+
)
443+
444+
response = order_manager.close_position(
445+
position.contractId, method="market"
446+
)
447+
448+
if response and response.success:
449+
print(
450+
f"✅ Closed position {position.contractId} (Order #{response.orderId})"
451+
)
452+
closed_count += 1
387453
else:
388-
print(f"i Order #{order_id} already closed/filled")
454+
print(f"❌ Failed to close position {position.contractId}")
389455
except Exception as e:
390-
print(f"❌ Error cancelling order #{order_id}: {e}")
456+
print(f"❌ Error closing position {position.contractId}: {e}")
457+
458+
print("\n📊 Cleanup completed:")
459+
print(f" Orders cancelled: {cancelled_count}")
460+
print(f" Positions closed: {closed_count}")
391461

392-
print(f"\n📊 Cleanup completed: {cancelled_count} orders cancelled")
462+
except Exception as e:
463+
print(f"❌ Cleanup error: {e}")
464+
print("⚠️ Manual cleanup may be required")
393465

394466
# Final status check
395467
print("\n" + "=" * 50)

0 commit comments

Comments
 (0)