tradepose-models 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. tradepose_models/__init__.py +44 -0
  2. tradepose_models/auth/__init__.py +13 -0
  3. tradepose_models/auth/api_keys.py +52 -0
  4. tradepose_models/auth/auth.py +20 -0
  5. tradepose_models/base.py +57 -0
  6. tradepose_models/billing/__init__.py +33 -0
  7. tradepose_models/billing/checkout.py +17 -0
  8. tradepose_models/billing/plans.py +32 -0
  9. tradepose_models/billing/subscriptions.py +34 -0
  10. tradepose_models/billing/usage.py +71 -0
  11. tradepose_models/broker/__init__.py +34 -0
  12. tradepose_models/broker/account_config.py +93 -0
  13. tradepose_models/broker/account_models.py +61 -0
  14. tradepose_models/broker/binding.py +54 -0
  15. tradepose_models/broker/connection_status.py +14 -0
  16. tradepose_models/commands/__init__.py +8 -0
  17. tradepose_models/commands/trader_command.py +80 -0
  18. tradepose_models/datafeed/__init__.py +19 -0
  19. tradepose_models/datafeed/events.py +132 -0
  20. tradepose_models/enums/__init__.py +47 -0
  21. tradepose_models/enums/account_source.py +42 -0
  22. tradepose_models/enums/broker_type.py +21 -0
  23. tradepose_models/enums/currency.py +17 -0
  24. tradepose_models/enums/engagement_phase.py +47 -0
  25. tradepose_models/enums/execution_mode.py +16 -0
  26. tradepose_models/enums/export_type.py +23 -0
  27. tradepose_models/enums/freq.py +32 -0
  28. tradepose_models/enums/indicator_type.py +46 -0
  29. tradepose_models/enums/operation_type.py +19 -0
  30. tradepose_models/enums/order_strategy.py +47 -0
  31. tradepose_models/enums/orderbook_event_type.py +29 -0
  32. tradepose_models/enums/persist_mode.py +28 -0
  33. tradepose_models/enums/stream.py +14 -0
  34. tradepose_models/enums/task_status.py +23 -0
  35. tradepose_models/enums/trade_direction.py +42 -0
  36. tradepose_models/enums/trend_type.py +22 -0
  37. tradepose_models/enums/weekday.py +30 -0
  38. tradepose_models/enums.py +32 -0
  39. tradepose_models/events/__init__.py +11 -0
  40. tradepose_models/events/order_events.py +79 -0
  41. tradepose_models/export/__init__.py +19 -0
  42. tradepose_models/export/request.py +52 -0
  43. tradepose_models/export/requests.py +75 -0
  44. tradepose_models/export/task_metadata.py +97 -0
  45. tradepose_models/gateway/__init__.py +19 -0
  46. tradepose_models/gateway/responses.py +37 -0
  47. tradepose_models/indicators/__init__.py +56 -0
  48. tradepose_models/indicators/base.py +42 -0
  49. tradepose_models/indicators/factory.py +254 -0
  50. tradepose_models/indicators/market_profile.md +60 -0
  51. tradepose_models/indicators/market_profile.py +333 -0
  52. tradepose_models/indicators/market_profile_developer.md +1782 -0
  53. tradepose_models/indicators/market_profile_trading.md +1060 -0
  54. tradepose_models/indicators/momentum.py +53 -0
  55. tradepose_models/indicators/moving_average.py +63 -0
  56. tradepose_models/indicators/other.py +40 -0
  57. tradepose_models/indicators/trend.py +80 -0
  58. tradepose_models/indicators/volatility.py +57 -0
  59. tradepose_models/instruments/__init__.py +13 -0
  60. tradepose_models/instruments/instrument.py +87 -0
  61. tradepose_models/scheduler/__init__.py +9 -0
  62. tradepose_models/scheduler/results.py +49 -0
  63. tradepose_models/schemas/__init__.py +15 -0
  64. tradepose_models/schemas/enhanced_ohlcv.py +111 -0
  65. tradepose_models/schemas/performance.py +40 -0
  66. tradepose_models/schemas/trades.py +64 -0
  67. tradepose_models/schemas.py +34 -0
  68. tradepose_models/shared.py +15 -0
  69. tradepose_models/strategy/__init__.py +52 -0
  70. tradepose_models/strategy/base.py +56 -0
  71. tradepose_models/strategy/blueprint.py +55 -0
  72. tradepose_models/strategy/config.py +142 -0
  73. tradepose_models/strategy/entities.py +104 -0
  74. tradepose_models/strategy/helpers.py +173 -0
  75. tradepose_models/strategy/indicator_spec.py +531 -0
  76. tradepose_models/strategy/performance.py +66 -0
  77. tradepose_models/strategy/portfolio.py +171 -0
  78. tradepose_models/strategy/registry.py +249 -0
  79. tradepose_models/strategy/requests.py +33 -0
  80. tradepose_models/strategy/trigger.py +77 -0
  81. tradepose_models/trading/__init__.py +55 -0
  82. tradepose_models/trading/engagement.py +160 -0
  83. tradepose_models/trading/orderbook.py +73 -0
  84. tradepose_models/trading/orders.py +137 -0
  85. tradepose_models/trading/positions.py +78 -0
  86. tradepose_models/trading/trader_commands.py +138 -0
  87. tradepose_models/trading/trades_execution.py +27 -0
  88. tradepose_models/types.py +35 -0
  89. tradepose_models/utils/__init__.py +13 -0
  90. tradepose_models/utils/rate_converter.py +112 -0
  91. tradepose_models/validators.py +32 -0
  92. tradepose_models-1.1.0.dist-info/METADATA +633 -0
  93. tradepose_models-1.1.0.dist-info/RECORD +94 -0
  94. tradepose_models-1.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,160 @@
1
+ """
2
+ Engagement Model (Issue #305, #320)
3
+
4
+ Provides the Engagement model for trade execution context.
5
+ Tracks the lifecycle of a trade from signal to completion.
6
+
7
+ 8-Phase lifecycle:
8
+ PENDING(0) → ENTERING(1) → HOLDING(2) → EXITING(3) → CLOSED(4)
9
+ │ │
10
+ ▼ ▼
11
+ FAILED(5) EXIT_FAILED(7)
12
+
13
+ CANCELLED(6) - Signal cancelled before execution
14
+ """
15
+
16
+ from datetime import datetime
17
+ from decimal import Decimal
18
+ from typing import Optional
19
+ from uuid import UUID
20
+
21
+ from pydantic import BaseModel, Field
22
+
23
+ from ..enums import EngagementPhase, TradeDirection
24
+
25
+
26
+ class Engagement(BaseModel):
27
+ """Trade execution context (Engagement).
28
+
29
+ Represents the binding between a trade signal and its execution.
30
+ One engagement can generate multiple orders (entry, SL, TP, exit).
31
+
32
+ Unique constraint: (user_id, account_id, binding_id, portfolio_id, blueprint_id, trade_id)
33
+ """
34
+
35
+ id: UUID = Field(..., description="Engagement UUID (primary key)")
36
+ user_id: UUID = Field(..., description="User UUID")
37
+ account_id: UUID = Field(..., description="Trading account UUID")
38
+ binding_id: UUID = Field(..., description="Account-Portfolio binding UUID")
39
+ portfolio_id: UUID = Field(..., description="Portfolio UUID")
40
+ blueprint_id: UUID = Field(..., description="Blueprint UUID")
41
+ trade_id: UUID = Field(..., description="Trade UUID (FK to trades)")
42
+
43
+ # FK fields for direct lookup
44
+ strategy_id: Optional[UUID] = Field(None, description="Strategy UUID")
45
+ portfolio_allocation_id: Optional[UUID] = Field(None, description="Portfolio allocation UUID")
46
+
47
+ # Phase system (8 states) - Issue #305
48
+ phase: EngagementPhase = Field(
49
+ default=EngagementPhase.PENDING,
50
+ description="Engagement phase (0-7): PENDING, ENTERING, HOLDING, EXITING, CLOSED, FAILED, CANCELLED, EXIT_FAILED",
51
+ )
52
+
53
+ # Latest tracking
54
+ is_latest: bool = Field(
55
+ default=True,
56
+ description="True if this is the most recent engagement for this trade context",
57
+ )
58
+
59
+ # Position sizing (MAE-based calculation)
60
+ target_quantity: Optional[Decimal] = Field(
61
+ None,
62
+ description="Calculated position size based on MAE formula",
63
+ )
64
+
65
+ # Trade direction and prices
66
+ direction: Optional[TradeDirection] = Field(
67
+ None,
68
+ description="Trade direction: Long or Short",
69
+ )
70
+ entry_price: Optional[Decimal] = Field(
71
+ None,
72
+ description="Target entry price from trade signal",
73
+ )
74
+ sl_price: Optional[Decimal] = Field(
75
+ None,
76
+ description="Stop loss price from trade signal",
77
+ )
78
+ tp_price: Optional[Decimal] = Field(
79
+ None,
80
+ description="Take profit price from trade signal",
81
+ )
82
+
83
+ # Fill tracking
84
+ filled_entry_qty: Decimal = Field(
85
+ default=Decimal("0"),
86
+ description="Quantity filled for entry order",
87
+ )
88
+ filled_exit_qty: Decimal = Field(
89
+ default=Decimal("0"),
90
+ description="Quantity filled for exit order",
91
+ )
92
+
93
+ # Trading instrument (may differ from signal instrument)
94
+ trading_instrument_id: Optional[int] = Field(
95
+ None,
96
+ description="Trading instrument ID (FK to data.instruments)",
97
+ )
98
+ symbol: Optional[str] = Field(
99
+ None,
100
+ description="Trading symbol for the mapped instrument",
101
+ )
102
+
103
+ # Timestamps
104
+ created_at: datetime = Field(..., description="Creation timestamp")
105
+ updated_at: datetime = Field(..., description="Last update timestamp")
106
+
107
+ # Phase helper properties
108
+ @property
109
+ def is_pending_phase(self) -> bool:
110
+ """Check if engagement is in PENDING phase."""
111
+ return self.phase == EngagementPhase.PENDING
112
+
113
+ @property
114
+ def is_entering_phase(self) -> bool:
115
+ """Check if engagement is in ENTERING phase."""
116
+ return self.phase == EngagementPhase.ENTERING
117
+
118
+ @property
119
+ def is_holding_phase(self) -> bool:
120
+ """Check if engagement is in HOLDING phase (position open)."""
121
+ return self.phase == EngagementPhase.HOLDING
122
+
123
+ @property
124
+ def is_exiting_phase(self) -> bool:
125
+ """Check if engagement is in EXITING phase."""
126
+ return self.phase == EngagementPhase.EXITING
127
+
128
+ @property
129
+ def is_closed_phase(self) -> bool:
130
+ """Check if engagement is in CLOSED phase."""
131
+ return self.phase == EngagementPhase.CLOSED
132
+
133
+ @property
134
+ def is_failed_phase(self) -> bool:
135
+ """Check if engagement is in FAILED phase."""
136
+ return self.phase == EngagementPhase.FAILED
137
+
138
+ @property
139
+ def is_cancelled_phase(self) -> bool:
140
+ """Check if engagement is in CANCELLED phase."""
141
+ return self.phase == EngagementPhase.CANCELLED
142
+
143
+ @property
144
+ def is_exit_failed_phase(self) -> bool:
145
+ """Check if engagement is in EXIT_FAILED phase."""
146
+ return self.phase == EngagementPhase.EXIT_FAILED
147
+
148
+ @property
149
+ def is_terminal(self) -> bool:
150
+ """Check if engagement is in a terminal state (no more transitions)."""
151
+ return self.phase in (
152
+ EngagementPhase.CLOSED,
153
+ EngagementPhase.FAILED,
154
+ EngagementPhase.CANCELLED,
155
+ )
156
+
157
+ @property
158
+ def needs_intervention(self) -> bool:
159
+ """Check if engagement needs manual intervention."""
160
+ return self.phase == EngagementPhase.EXIT_FAILED
@@ -0,0 +1,73 @@
1
+ """
2
+ Orderbook Model
3
+
4
+ Provides the OrderbookEntry model for event sourcing of order lifecycle.
5
+ Each event in the order lifecycle is recorded as a separate entry.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from decimal import Decimal
10
+ from typing import Optional
11
+ from uuid import UUID
12
+
13
+ from pydantic import BaseModel, Field
14
+
15
+ from ..enums import OrderbookEventType
16
+ from .orders import OrderSide, OrderStatus, OrderType
17
+
18
+
19
+ class OrderbookEntry(BaseModel):
20
+ """Orderbook event entry (Event Sourcing).
21
+
22
+ Records each event in the order lifecycle for audit and tracking.
23
+ Each order state change creates a new entry (immutable log).
24
+
25
+ Event Types:
26
+ - ORDER_CREATED (0): Order submitted to broker
27
+ - ORDER_MODIFIED (1): Order modified (price, quantity)
28
+ - ORDER_CANCELLED (2): Order cancelled
29
+ - PARTIAL_FILL (3): Order partially filled
30
+ - FULLY_FILLED (4): Order fully filled
31
+ - REJECTED (5): Order rejected by broker
32
+ """
33
+
34
+ id: UUID = Field(..., description="Entry UUID (primary key)")
35
+ user_id: UUID = Field(..., description="User UUID")
36
+ engagement_id: UUID = Field(..., description="Engagement UUID (FK)")
37
+
38
+ event_type: OrderbookEventType = Field(..., description="Event type (SMALLINT: 0-5)")
39
+ raw_data: dict = Field(default_factory=dict, description="Broker raw response (JSONB)")
40
+
41
+ # Order details
42
+ symbol: str = Field(..., description="Trading symbol")
43
+ side: OrderSide = Field(..., description="Order side (BUY/SELL)")
44
+ order_type: OrderType = Field(..., description="Order type")
45
+ quantity: Decimal = Field(..., description="Order quantity")
46
+ filled_quantity: Decimal = Field(
47
+ default=Decimal("0"), description="Filled quantity (for partial fills)"
48
+ )
49
+ price: Optional[Decimal] = Field(None, description="Order price (for limit orders)")
50
+ filled_price: Optional[Decimal] = Field(None, description="Average filled price")
51
+
52
+ # Broker tracking
53
+ broker_order_id: str = Field(..., description="Broker's order ID")
54
+ status: OrderStatus = Field(..., description="Order status")
55
+
56
+ # Timestamps
57
+ created_at: datetime = Field(..., description="Event timestamp")
58
+ updated_at: datetime = Field(..., description="Last update timestamp")
59
+
60
+ @property
61
+ def is_filled(self) -> bool:
62
+ """Check if order is fully filled."""
63
+ return self.event_type == OrderbookEventType.FULLY_FILLED
64
+
65
+ @property
66
+ def is_partial(self) -> bool:
67
+ """Check if order is partially filled."""
68
+ return self.event_type == OrderbookEventType.PARTIAL_FILL
69
+
70
+ @property
71
+ def remaining_quantity(self) -> Decimal:
72
+ """Calculate remaining quantity."""
73
+ return self.quantity - self.filled_quantity
@@ -0,0 +1,137 @@
1
+ """Order models for unified trading interface."""
2
+
3
+ from datetime import datetime
4
+ from decimal import Decimal
5
+ from enum import Enum
6
+ from typing import Optional
7
+ from uuid import UUID
8
+
9
+ from pydantic import BaseModel, Field
10
+
11
+ # Import OrderStrategy from existing enums module
12
+ from tradepose_models.enums.order_strategy import OrderStrategy
13
+
14
+
15
+ class OrderSide(str, Enum):
16
+ """Order side."""
17
+
18
+ BUY = "buy"
19
+ SELL = "sell"
20
+
21
+
22
+ class OrderType(str, Enum):
23
+ """Order types."""
24
+
25
+ MARKET = "market"
26
+ LIMIT = "limit"
27
+ STOP_MARKET = "stop_market"
28
+ STOP_LIMIT = "stop_limit"
29
+ TAKE_PROFIT_MARKET = "take_profit_market"
30
+ TAKE_PROFIT_LIMIT = "take_profit_limit"
31
+
32
+
33
+ class OrderStatus(str, Enum):
34
+ """Order status."""
35
+
36
+ PENDING_NEW = "pending_new"
37
+ NEW = "new"
38
+ PARTIALLY_FILLED = "partially_filled"
39
+ FILLED = "filled"
40
+ CANCELLED = "cancelled"
41
+ REJECTED = "rejected"
42
+ EXPIRED = "expired"
43
+
44
+
45
+ class TimeInForce(str, Enum):
46
+ """Time in force."""
47
+
48
+ GTC = "gtc" # Good Till Cancel
49
+ IOC = "ioc" # Immediate or Cancel
50
+ FOK = "fok" # Fill or Kill
51
+
52
+
53
+ class OrderSubmitRequest(BaseModel):
54
+ """Unified order submission request."""
55
+
56
+ user_id: UUID
57
+ account_id: UUID
58
+ symbol: str = Field(..., description="Unified symbol (e.g., BTC-USDT)")
59
+ side: OrderSide
60
+ order_type: OrderType
61
+ quantity: Decimal
62
+ price: Optional[Decimal] = None
63
+ stop_price: Optional[Decimal] = None
64
+ time_in_force: TimeInForce = TimeInForce.GTC
65
+ client_order_id: Optional[str] = None
66
+ reduce_only: bool = False
67
+
68
+ # Trade/Portfolio context
69
+ snapshot_price: Optional[Decimal] = Field(None, description="Market price at submission")
70
+ trade_id: Optional[str] = Field(None, description="Backtest trade ID")
71
+ portfolio_id: Optional[str] = Field(None, description="Portfolio ID")
72
+ order_strategy: Optional[OrderStrategy] = Field(None, description="Execution strategy")
73
+
74
+ extra_params: dict = Field(default_factory=dict)
75
+
76
+
77
+ class Order(BaseModel):
78
+ """Unified order model."""
79
+
80
+ order_id: str
81
+ client_order_id: Optional[str]
82
+ user_id: UUID
83
+ account_id: UUID
84
+ broker: str
85
+ symbol: str = Field(..., description="Unified symbol")
86
+ broker_symbol: str = Field(..., description="Broker-specific symbol")
87
+ side: OrderSide
88
+ order_type: OrderType
89
+ quantity: Decimal
90
+ price: Optional[Decimal]
91
+ stop_price: Optional[Decimal]
92
+ filled_quantity: Decimal
93
+ remaining_quantity: Decimal
94
+ average_fill_price: Optional[Decimal]
95
+ status: OrderStatus
96
+ time_in_force: TimeInForce
97
+ created_at: datetime
98
+ updated_at: datetime
99
+ commission: Optional[Decimal] = None
100
+ commission_asset: Optional[str] = None
101
+
102
+ # Trade/Portfolio tracking
103
+ trade_id: Optional[str] = None
104
+ portfolio_id: Optional[str] = None
105
+ order_strategy: Optional[OrderStrategy] = None
106
+
107
+ raw_data: Optional[dict] = None # Broker's raw response
108
+
109
+
110
+ class ExecutionReport(BaseModel):
111
+ """Unified execution report (fill notification)."""
112
+
113
+ execution_id: str
114
+ order_id: str
115
+ client_order_id: Optional[str]
116
+ user_id: UUID
117
+ account_id: UUID
118
+ broker: str
119
+ symbol: str
120
+ broker_symbol: str
121
+ side: OrderSide
122
+ last_filled_quantity: Decimal
123
+ last_filled_price: Optional[Decimal]
124
+ cumulative_filled_quantity: Decimal
125
+ remaining_quantity: Decimal
126
+ order_status: OrderStatus
127
+ commission: Decimal
128
+ commission_asset: str
129
+ transact_time: datetime
130
+ received_at: datetime
131
+
132
+ # Trade/Portfolio tracking
133
+ trade_id: Optional[str] = None
134
+ portfolio_id: Optional[str] = None
135
+ order_strategy: Optional[OrderStrategy] = None
136
+
137
+ raw_data: Optional[dict] = None
@@ -0,0 +1,78 @@
1
+ """Position models."""
2
+
3
+ from datetime import datetime
4
+ from decimal import Decimal
5
+ from enum import Enum
6
+ from typing import Optional
7
+ from uuid import UUID
8
+
9
+ from pydantic import BaseModel, Field
10
+
11
+
12
+ class PositionSide(str, Enum):
13
+ """Position side."""
14
+
15
+ LONG = "long"
16
+ SHORT = "short"
17
+
18
+
19
+ class Position(BaseModel):
20
+ """Unified position model."""
21
+
22
+ # Core fields (required)
23
+ symbol: str # Unified symbol
24
+ broker_symbol: str # Broker-specific symbol
25
+ side: PositionSide
26
+ quantity: Decimal
27
+ entry_price: Decimal # Average cost
28
+ current_price: Decimal
29
+ unrealized_pnl: Decimal
30
+
31
+ # With defaults (was required, now has sensible defaults)
32
+ realized_pnl: Decimal = Decimal(0)
33
+ created_at: datetime = Field(default_factory=datetime.now)
34
+ updated_at: datetime = Field(default_factory=datetime.now)
35
+
36
+ # Existing optional fields
37
+ margin_used: Optional[Decimal] = None
38
+ leverage: Optional[Decimal] = None
39
+ raw_data: Optional[dict] = None
40
+
41
+ # Broker-specific identifiers (optional)
42
+ position_id: Optional[str] = None
43
+ user_id: Optional[UUID] = None
44
+ account_id: Optional[UUID] = None
45
+ broker: Optional[str] = None
46
+ opened_at: Optional[datetime] = None
47
+
48
+ # Risk management (optional)
49
+ stop_loss: Optional[Decimal] = None
50
+ take_profit: Optional[Decimal] = None
51
+
52
+ # MT5-specific (optional)
53
+ swap: Optional[Decimal] = None
54
+ magic: Optional[int] = None
55
+ comment: Optional[str] = None
56
+
57
+
58
+ class ClosedPosition(BaseModel):
59
+ """Closed position (historical)."""
60
+
61
+ # Required fields
62
+ symbol: str
63
+ side: PositionSide
64
+ quantity: Decimal
65
+ entry_price: Decimal
66
+ exit_price: Decimal
67
+ realized_pnl: Decimal
68
+ commission: Decimal
69
+ opened_at: datetime
70
+ closed_at: datetime
71
+
72
+ # Broker-specific (optional)
73
+ position_id: Optional[str] = None
74
+ user_id: Optional[UUID] = None
75
+ account_id: Optional[UUID] = None
76
+ broker: Optional[str] = None
77
+ broker_symbol: Optional[str] = None
78
+ swap: Optional[Decimal] = None
@@ -0,0 +1,138 @@
1
+ """Trader command models for Redis Stream communication (Issue #307, #320).
2
+
3
+ Pydantic models for trader commands published to Redis Streams:
4
+ - ExecuteOrderCommand: Open a new position
5
+ - CancelOrderCommand: Cancel an existing order
6
+ - ModifyOrderCommand: Modify SL/TP on existing order
7
+ - SyncBrokerStatusCommand: Request broker status sync
8
+
9
+ Stream pattern: trader:commands:{user_id}:{node_seq}:{slot_idx}
10
+ """
11
+
12
+ from datetime import datetime
13
+ from decimal import Decimal
14
+ from typing import Literal, Optional
15
+ from uuid import UUID
16
+
17
+ from pydantic import BaseModel, Field
18
+
19
+ from tradepose_models.enums import TradeDirection
20
+
21
+
22
+ class BaseTraderCommand(BaseModel):
23
+ """Base class for all trader commands."""
24
+
25
+ timestamp: datetime = Field(
26
+ ...,
27
+ description="Command creation timestamp (UTC)",
28
+ )
29
+
30
+
31
+ class ExecuteOrderCommand(BaseTraderCommand):
32
+ """Command to execute a new order.
33
+
34
+ Published when an engagement is created and ready for execution.
35
+ Contains all information needed to place entry order with SL/TP.
36
+ """
37
+
38
+ command_type: Literal["execute_order"] = Field(
39
+ default="execute_order",
40
+ description="Command type identifier",
41
+ )
42
+ engagement_id: UUID = Field(
43
+ ...,
44
+ description="Engagement UUID for tracking",
45
+ )
46
+ account_id: UUID = Field(
47
+ ...,
48
+ description="Trading account UUID",
49
+ )
50
+ symbol: str = Field(
51
+ ...,
52
+ description="Trading symbol (e.g., XAUUSD, MNQ)",
53
+ )
54
+ direction: TradeDirection = Field(
55
+ ...,
56
+ description="Trade direction: Long or Short",
57
+ )
58
+ quantity: Decimal = Field(
59
+ ...,
60
+ gt=0,
61
+ description="Order quantity (lots)",
62
+ )
63
+ entry_price: Decimal = Field(
64
+ ...,
65
+ gt=0,
66
+ description="Target entry price",
67
+ )
68
+ sl_price: Optional[Decimal] = Field(
69
+ None,
70
+ description="Stop loss price (optional)",
71
+ )
72
+ tp_price: Optional[Decimal] = Field(
73
+ None,
74
+ description="Take profit price (optional)",
75
+ )
76
+
77
+
78
+ class CancelOrderCommand(BaseTraderCommand):
79
+ """Command to cancel an existing order."""
80
+
81
+ command_type: Literal["cancel_order"] = Field(
82
+ default="cancel_order",
83
+ description="Command type identifier",
84
+ )
85
+ engagement_id: UUID = Field(
86
+ ...,
87
+ description="Engagement UUID for tracking",
88
+ )
89
+ account_id: UUID = Field(
90
+ ...,
91
+ description="Trading account UUID",
92
+ )
93
+ broker_order_id: Optional[str] = Field(
94
+ None,
95
+ description="Broker's order ID to cancel (if known)",
96
+ )
97
+
98
+
99
+ class ModifyOrderCommand(BaseTraderCommand):
100
+ """Command to modify an existing order's SL/TP."""
101
+
102
+ command_type: Literal["modify_order"] = Field(
103
+ default="modify_order",
104
+ description="Command type identifier",
105
+ )
106
+ engagement_id: UUID = Field(
107
+ ...,
108
+ description="Engagement UUID for tracking",
109
+ )
110
+ account_id: UUID = Field(
111
+ ...,
112
+ description="Trading account UUID",
113
+ )
114
+ broker_order_id: str = Field(
115
+ ...,
116
+ description="Broker's order ID to modify",
117
+ )
118
+ new_sl_price: Optional[Decimal] = Field(
119
+ None,
120
+ description="New stop loss price",
121
+ )
122
+ new_tp_price: Optional[Decimal] = Field(
123
+ None,
124
+ description="New take profit price",
125
+ )
126
+
127
+
128
+ class SyncBrokerStatusCommand(BaseTraderCommand):
129
+ """Command to request broker status synchronization."""
130
+
131
+ command_type: Literal["sync_broker_status"] = Field(
132
+ default="sync_broker_status",
133
+ description="Command type identifier",
134
+ )
135
+ account_id: UUID = Field(
136
+ ...,
137
+ description="Trading account UUID to sync",
138
+ )
@@ -0,0 +1,27 @@
1
+ """Trade execution record models."""
2
+
3
+ from datetime import datetime
4
+ from decimal import Decimal
5
+ from typing import Literal, Optional
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from tradepose_models.trading.orders import OrderSide
10
+
11
+
12
+ class TradeExecution(BaseModel):
13
+ """Trade execution record (actual fill)."""
14
+
15
+ trade_id: str
16
+ order_id: str
17
+ client_order_id: Optional[str]
18
+ symbol: str
19
+ broker_symbol: str
20
+ side: OrderSide
21
+ price: Decimal
22
+ quantity: Decimal
23
+ commission: Decimal
24
+ commission_asset: str
25
+ commission_type: Literal["maker", "taker", "fixed"]
26
+ timestamp: datetime
27
+ raw_data: Optional[dict] = None
@@ -0,0 +1,35 @@
1
+ """Common type definitions (通用類型定義).
2
+
3
+ This module contains type aliases and custom types used across the platform
4
+ to improve code clarity and type safety.
5
+
6
+ 這個模組包含平台上使用的類型別名和自定義類型,以提高代碼清晰度和類型安全性。
7
+
8
+ Example usage:
9
+ from tradepose_models.types import UserId, APIKeyHash, Timestamp
10
+
11
+ def get_user(user_id: UserId) -> dict:
12
+ # Type hints make the code more readable
13
+ return {"id": user_id}
14
+
15
+ def verify_key(key_hash: APIKeyHash) -> bool:
16
+ # Custom types document intent
17
+ return check_hash(key_hash)
18
+ """
19
+
20
+
21
+ # Placeholder for shared type definitions
22
+ # Types will be added here as needed
23
+ # 共用類型定義將根據需要添加到這裡
24
+
25
+ # Example structure:
26
+ # UserId = NewType('UserId', str)
27
+ # """User identifier type (用戶標識符類型)."""
28
+ #
29
+ # APIKeyHash = NewType('APIKeyHash', str)
30
+ # """Hashed API key type (API 密鑰哈希類型)."""
31
+ #
32
+ # Timestamp = NewType('Timestamp', datetime)
33
+ # """Timestamp type for consistency (時間戳類型以保持一致性)."""
34
+
35
+ __all__ = []
@@ -0,0 +1,13 @@
1
+ """Utility modules for TradePose models."""
2
+
3
+ from .rate_converter import (
4
+ DEFAULT_RATES,
5
+ RateConverter,
6
+ get_default_converter,
7
+ )
8
+
9
+ __all__ = [
10
+ "DEFAULT_RATES",
11
+ "RateConverter",
12
+ "get_default_converter",
13
+ ]