Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
980 changes: 626 additions & 354 deletions examples/15_order_lifecycle_tracking.py

Large diffs are not rendered by default.

65 changes: 54 additions & 11 deletions scripts/check_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@ def visit_ClassDef(self, node: ast.ClassDef) -> None:
# Explicitly exclude utility classes that don't need to be async
excluded_classes = [
"ConfigManager", # Configuration management - sync utility
"ErrorContext", # Error context manager - has async context but methods can be sync
"Deprecation", # Deprecation utilities
"Logger", # Logging utilities
"ErrorContext", # Error context manager - has async context but methods can be sync
"Deprecation", # Deprecation utilities
"Logger", # Logging utilities
]

if node.name in excluded_classes:
is_async_class = False
else:
# Check if it's a class that should be async based on patterns
is_async_class = (
("Manager" in node.name and node.name != "ConfigManager") # Managers except ConfigManager
(
"Manager" in node.name and node.name != "ConfigManager"
) # Managers except ConfigManager
or "Client" in node.name
or "Suite" in node.name
or "Realtime" in node.name
Expand Down Expand Up @@ -101,29 +103,64 @@ def _has_io_operations(self, node: ast.FunctionDef) -> bool:

# Check for known I/O objects and their methods
if obj_name in ["httpx", "aiohttp", "requests", "urllib"]:
if attr_name in ["get", "post", "put", "delete", "patch", "request"]:
if attr_name in [
"get",
"post",
"put",
"delete",
"patch",
"request",
]:
return True
elif obj_name in ["socket", "websocket", "ws"]:
if attr_name in ["connect", "send", "recv", "close"]:
return True
elif obj_name in ["file", "f", "fp"]:
if attr_name in ["read", "write", "seek", "tell"]:
return True
elif obj_name in ["db", "database", "conn", "connection", "cursor"]:
elif obj_name in [
"db",
"database",
"conn",
"connection",
"cursor",
]:
if attr_name in ["execute", "fetch", "commit", "rollback"]:
return True

# Check for self.client or self.http calls (common in SDK)
if isinstance(item.func.value, ast.Attribute):
if hasattr(item.func.value, "attr"):
obj_attr = item.func.value.attr
if obj_attr in ["client", "http", "session", "api", "_client", "_http"]:
if attr_name in ["get", "post", "put", "delete", "patch", "request", "fetch"]:
if obj_attr in [
"client",
"http",
"session",
"api",
"_client",
"_http",
]:
if attr_name in [
"get",
"post",
"put",
"delete",
"patch",
"request",
"fetch",
]:
return True

# Check for common async I/O patterns that should be async
if attr_name in ["request", "fetch_data", "api_call", "send_request",
"make_request", "http_get", "http_post"]:
if attr_name in [
"request",
"fetch_data",
"api_call",
"send_request",
"make_request",
"http_get",
"http_post",
]:
return True

elif isinstance(item.func, ast.Name):
Expand All @@ -148,7 +185,13 @@ def _is_simple_getter(self, node: ast.FunctionDef) -> bool:
if isinstance(item, ast.Call):
# Check if any calls might be I/O
if isinstance(item.func, ast.Attribute):
if item.func.attr in ["request", "fetch", "api_call", "http_get", "http_post"]:
if item.func.attr in [
"request",
"fetch",
"api_call",
"http_get",
"http_post",
]:
has_io_call = True
break
elif isinstance(item.func, ast.Name):
Expand Down
17 changes: 1 addition & 16 deletions src/project_x_py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,18 +180,7 @@
ScalpingTemplate,
get_template,
)

# Deprecated: These are re-exported for backward compatibility only
# Use TradingSuite.track_order() and TradingSuite.order_chain() instead
from project_x_py.order_tracker import (
OrderChainBuilder, # Deprecated: Use TradingSuite.order_chain()
OrderLifecycleError,
OrderTracker, # Deprecated: Use TradingSuite.track_order()
)
from project_x_py.orderbook import (
OrderBook,
create_orderbook,
)
from project_x_py.orderbook import OrderBook
from project_x_py.position_manager import PositionManager
from project_x_py.realtime import ProjectXRealtimeClient as ProjectXRealtimeClient
from project_x_py.realtime_data_manager import RealtimeDataManager
Expand Down Expand Up @@ -249,13 +238,10 @@
"Order",
# Core classes (now async-only but with original names)
"OrderBook",
"OrderChainBuilder",
"OrderLifecycleError",
"OrderManager",
"OrderManagerConfig",
"OrderPlaceResponse",
"OrderTemplate",
"OrderTracker",
"OrderSide",
"OrderStatus",
"OrderType",
Expand Down Expand Up @@ -314,7 +300,6 @@
"calculate_vwap",
"calculate_williams_r",
"create_custom_config",
"create_orderbook",
"get_env_var",
"load_default_config",
"load_topstepx_config",
Expand Down
24 changes: 0 additions & 24 deletions src/project_x_py/client/trading.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ async def main():

from project_x_py.exceptions import ProjectXError
from project_x_py.models import Position, Trade
from project_x_py.utils.deprecation import deprecated

logger = logging.getLogger(__name__)

Expand All @@ -99,29 +98,6 @@ async def _make_request(
"""Provided by HttpMixin."""
_ = (method, endpoint, data, params, headers, retry_count)

@deprecated(
reason="Method renamed for API consistency",
version="3.0.0",
removal_version="4.0.0",
replacement="search_open_positions()",
)
async def get_positions(self) -> list[Position]:
"""
DEPRECATED: Get all open positions for the authenticated account.

This method is deprecated and will be removed in a future version.
Please use `search_open_positions()` instead, which provides the same
functionality with a more consistent API endpoint.

Args:
self: The client instance.

Returns:
A list of Position objects representing current holdings.
"""
# Deprecation warning handled by decorator
return await self.search_open_positions()

async def search_open_positions(
self, account_id: int | None = None
) -> list[Position]:
Expand Down
22 changes: 1 addition & 21 deletions src/project_x_py/order_manager/tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,11 @@ def on_order_fill(order_data):
import logging
import time
from collections import defaultdict, deque
from collections.abc import Callable, Coroutine
from collections.abc import Coroutine
from typing import TYPE_CHECKING, Any, cast

from cachetools import TTLCache

from project_x_py.utils.deprecation import deprecated

if TYPE_CHECKING:
from project_x_py.event_bus import EventBus
from project_x_py.types import OrderManagerProtocol
Expand Down Expand Up @@ -1024,24 +1022,6 @@ async def get_tracked_order_status(
order_data = self.tracked_orders.get(order_id)
return order_data if order_data is not None else None

@deprecated(
reason="Use TradingSuite.on() with EventType enum for event handling",
version="3.1.0",
removal_version="4.0.0",
replacement="TradingSuite.on(EventType.ORDER_FILLED, callback)",
)
def add_callback(
self,
_event_type: str,
_callback: Callable[[dict[str, Any]], None],
) -> None:
"""
DEPRECATED: Use TradingSuite.on() with EventType enum instead.

This method is provided for backward compatibility only and will be removed in v4.0.
"""
# Deprecation warning handled by decorator

async def _trigger_callbacks(self, event_type: str, data: Any) -> None:
"""
Trigger all callbacks registered for a specific event type.
Expand Down
Loading
Loading