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,44 @@
1
+ """TradePose shared models package.
2
+
3
+ This package contains Pydantic models, enums, schemas, and types shared
4
+ across the TradePose platform, including gateway, client SDK, and other
5
+ components.
6
+
7
+ Organization:
8
+ - base: Base Pydantic model with standardized configuration
9
+ - enums: Shared enumerations
10
+ - events: Order and trading event models
11
+ - schemas: Shared data schemas (Polars)
12
+ - auth: Authentication and API key models
13
+ - billing: Billing, subscription, and usage models
14
+ - broker: Broker account and binding models
15
+ - export: Export task and result models
16
+ - gateway: Gateway API response models
17
+ - indicators: Indicator specifications
18
+ - strategy: Strategy configuration models
19
+ - trading: Trading-related models (orders, positions, engagements)
20
+ - utils: Utility modules (rate conversion, etc.)
21
+ - validators: Shared validation utilities
22
+ - types: Common type definitions
23
+
24
+ Example usage:
25
+ from tradepose_models.base import BaseModel
26
+ from tradepose_models.enums import TaskStatus, ExportType
27
+ from tradepose_models.auth import APIKeyCreate
28
+ from tradepose_models.billing import PlanResponse
29
+ from tradepose_models.export import ExportTaskResponse
30
+ from tradepose_models.utils import RateConverter, get_default_converter
31
+ """
32
+
33
+ from .base import BaseModel
34
+ from .utils import DEFAULT_RATES, RateConverter, get_default_converter
35
+
36
+ __version__ = "0.1.0"
37
+
38
+ __all__ = [
39
+ "__version__",
40
+ "BaseModel",
41
+ "DEFAULT_RATES",
42
+ "RateConverter",
43
+ "get_default_converter",
44
+ ]
@@ -0,0 +1,13 @@
1
+ """Authentication and API key models."""
2
+
3
+ from .api_keys import APIKeyCreate, APIKeyCreateResponse, APIKeyListResponse, APIKeyResponse
4
+ from .auth import AuthContext, AuthUser
5
+
6
+ __all__ = [
7
+ "APIKeyCreate",
8
+ "APIKeyResponse",
9
+ "APIKeyCreateResponse",
10
+ "APIKeyListResponse",
11
+ "AuthUser",
12
+ "AuthContext",
13
+ ]
@@ -0,0 +1,52 @@
1
+ """API key management models."""
2
+
3
+ from datetime import datetime
4
+ from uuid import UUID
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+
8
+
9
+ class APIKeyCreate(BaseModel):
10
+ """Request model for creating a new API key."""
11
+
12
+ name: str = Field(
13
+ ...,
14
+ min_length=1,
15
+ max_length=100,
16
+ description="Human-readable name for the API key",
17
+ )
18
+
19
+
20
+ class APIKeyResponse(BaseModel):
21
+ """Response model for API key (without plaintext key)."""
22
+
23
+ model_config = ConfigDict(from_attributes=True)
24
+
25
+ id: UUID
26
+ user_id: str # Clerk ID
27
+ name: str
28
+ revoked: bool
29
+ last_used: datetime | None
30
+ created_at: datetime
31
+
32
+
33
+ class APIKeyCreateResponse(BaseModel):
34
+ """Response model when creating a new API key (includes plaintext key ONCE)."""
35
+
36
+ model_config = ConfigDict(from_attributes=True)
37
+
38
+ id: UUID
39
+ user_id: str # Clerk ID
40
+ name: str
41
+ api_key: str = Field(
42
+ ...,
43
+ description="Plaintext API key - save this securely, it won't be shown again!",
44
+ )
45
+ created_at: datetime
46
+
47
+
48
+ class APIKeyListResponse(BaseModel):
49
+ """Response model for listing API keys."""
50
+
51
+ keys: list[APIKeyResponse]
52
+ total: int
@@ -0,0 +1,20 @@
1
+ """Authentication context models."""
2
+
3
+ from uuid import UUID
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class AuthUser(BaseModel):
9
+ """Authenticated user information."""
10
+
11
+ user_id: str # Clerk ID (primary key)
12
+ auth_method: str = Field(..., description="Authentication method used: 'jwt' or 'api_key'")
13
+ api_key_id: UUID | None = None # Present if authenticated via API key
14
+
15
+
16
+ class AuthContext(BaseModel):
17
+ """Full authentication context for a request."""
18
+
19
+ user: AuthUser
20
+ is_authenticated: bool = True
@@ -0,0 +1,57 @@
1
+ """
2
+ Base Pydantic models with standardized configuration.
3
+
4
+ This module provides a base model that all TradePose models should inherit from.
5
+ It includes standardized serialization rules, particularly for enum handling.
6
+ """
7
+
8
+ from pydantic import BaseModel as PydanticBaseModel
9
+ from pydantic import ConfigDict
10
+
11
+
12
+ class BaseModel(PydanticBaseModel):
13
+ """
14
+ Base model with standardized configuration for all TradePose models.
15
+
16
+ Configuration:
17
+ - use_enum_values=False: Enums serialize to their NAME (uppercase string) instead of value
18
+ Example: TaskStatus.PENDING → "PENDING" (not 0)
19
+ - validate_assignment=True: Validate field assignments after model creation
20
+ - arbitrary_types_allowed=True: Allow custom types (e.g., Redis connections)
21
+
22
+ Internal Storage vs API Response:
23
+ - PostgreSQL: Stores enums as SMALLINT (0, 1, 2, 3)
24
+ - Python Code: Uses int Enum (TaskStatus.PENDING = 0)
25
+ - Redis: Stores as integer in JSON ({"status": 0})
26
+ - API JSON Output: Serializes as uppercase string ({"status": "PENDING"})
27
+
28
+ This ensures:
29
+ 1. Efficient storage (integers in database)
30
+ 2. Type safety in code (enum objects)
31
+ 3. Readable API responses (uppercase strings)
32
+ 4. Backward compatibility (string format maintained)
33
+
34
+ Example:
35
+ ```python
36
+ from tradepose_models.base import BaseModel
37
+ from tradepose_models.enums import TaskStatus
38
+
39
+ class MyModel(BaseModel):
40
+ status: TaskStatus
41
+
42
+ model = MyModel(status=TaskStatus.PENDING)
43
+ print(model.model_dump()) # {'status': TaskStatus.PENDING}
44
+ print(model.model_dump_json()) # '{"status":"PENDING"}'
45
+ ```
46
+ """
47
+
48
+ model_config = ConfigDict(
49
+ # Serialize enums to name (uppercase string) for API responses
50
+ use_enum_values=False,
51
+ # Validate assignments after model creation
52
+ validate_assignment=True,
53
+ # Allow arbitrary types (e.g., Redis connections, asyncpg pools)
54
+ arbitrary_types_allowed=True,
55
+ # Use attribute docstrings for schema descriptions
56
+ use_attribute_docstrings=True,
57
+ )
@@ -0,0 +1,33 @@
1
+ """Billing and subscription models."""
2
+
3
+ from .checkout import CheckoutRequest, CheckoutResponse
4
+ from .plans import PlanLimitsResponse, PlanResponse, PlansListResponse
5
+ from .subscriptions import SubscriptionDetailResponse, SubscriptionResponse
6
+ from .usage import (
7
+ CurrentUsageResponse,
8
+ DetailedUsageResponse,
9
+ UsageDayResponse,
10
+ UsageHistoryResponse,
11
+ UsageStatsResponse,
12
+ UsageWindowResponse,
13
+ )
14
+
15
+ __all__ = [
16
+ # Checkout
17
+ "CheckoutRequest",
18
+ "CheckoutResponse",
19
+ # Plans
20
+ "PlanLimitsResponse",
21
+ "PlanResponse",
22
+ "PlansListResponse",
23
+ # Subscriptions
24
+ "SubscriptionResponse",
25
+ "SubscriptionDetailResponse",
26
+ # Usage
27
+ "UsageDayResponse",
28
+ "CurrentUsageResponse",
29
+ "UsageHistoryResponse",
30
+ "UsageStatsResponse",
31
+ "UsageWindowResponse",
32
+ "DetailedUsageResponse",
33
+ ]
@@ -0,0 +1,17 @@
1
+ """Checkout session models."""
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class CheckoutRequest(BaseModel):
7
+ """Request model for creating a checkout session."""
8
+
9
+ plan_tier: str = Field(..., description="Plan tier: free, pro, enterprise")
10
+ billing_cycle: str = Field(..., description="Billing cycle: monthly, yearly")
11
+
12
+
13
+ class CheckoutResponse(BaseModel):
14
+ """Response model for checkout session."""
15
+
16
+ checkout_url: str = Field(..., description="Lemon Squeezy checkout URL")
17
+ variant_id: str = Field(..., description="Lemon Squeezy variant ID")
@@ -0,0 +1,32 @@
1
+ """Subscription plan models."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class PlanLimitsResponse(BaseModel):
7
+ """Plan limits response model."""
8
+
9
+ requests_per_minute: int
10
+ monthly_quota: int
11
+ max_concurrent_tasks: int
12
+ max_strategies: int
13
+ priority_queue: bool
14
+ support_level: str
15
+
16
+
17
+ class PlanResponse(BaseModel):
18
+ """Subscription plan response model."""
19
+
20
+ tier: str
21
+ name: str
22
+ description: str
23
+ price_monthly: float
24
+ price_yearly: float
25
+ limits: PlanLimitsResponse
26
+ features: list[str]
27
+
28
+
29
+ class PlansListResponse(BaseModel):
30
+ """Response model for listing all plans."""
31
+
32
+ plans: list[PlanResponse]
@@ -0,0 +1,34 @@
1
+ """Subscription models."""
2
+
3
+ from datetime import datetime
4
+ from uuid import UUID
5
+
6
+ from pydantic import BaseModel, ConfigDict
7
+
8
+ from .plans import PlanResponse
9
+
10
+
11
+ class SubscriptionResponse(BaseModel):
12
+ """Response model for subscription (without sensitive data)."""
13
+
14
+ model_config = ConfigDict(from_attributes=True)
15
+
16
+ id: UUID
17
+ user_id: UUID # User ID (UUID)
18
+ lemonsqueezy_subscription_id: str | None = None
19
+ lemonsqueezy_customer_id: str | None = None
20
+ plan: str
21
+ status: str
22
+ current_period_start: datetime | None = None
23
+ current_period_end: datetime | None = None
24
+ created_at: datetime
25
+ updated_at: datetime
26
+
27
+
28
+ class SubscriptionDetailResponse(BaseModel):
29
+ """Detailed subscription response with plan info."""
30
+
31
+ subscription: SubscriptionResponse | None
32
+ current_plan: PlanResponse
33
+ usage_current_month: int = 0
34
+ usage_limit: int = 0
@@ -0,0 +1,71 @@
1
+ """Usage tracking models."""
2
+
3
+ from datetime import date, datetime
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class UsageDayResponse(BaseModel):
9
+ """Daily usage record response."""
10
+
11
+ usage_date: date = Field(..., description="Date of usage")
12
+ requests: int = Field(..., description="Number of requests on this date")
13
+
14
+
15
+ class CurrentUsageResponse(BaseModel):
16
+ """Current month usage response."""
17
+
18
+ user_id: str # Clerk ID
19
+ current_month: str = Field(..., description="Current month (YYYY-MM)")
20
+ usage: int = Field(..., description="Total requests this month")
21
+ limit: int = Field(..., description="Monthly quota limit")
22
+ remaining: int = Field(..., description="Remaining requests")
23
+ percentage_used: float = Field(..., description="Percentage of quota used (0-100)")
24
+
25
+
26
+ class UsageHistoryResponse(BaseModel):
27
+ """Historical usage response."""
28
+
29
+ user_id: str # Clerk ID
30
+ start_date: date
31
+ end_date: date
32
+ total_requests: int = Field(..., description="Total requests in date range")
33
+ daily_usage: list[UsageDayResponse] = Field(default_factory=list, description="Daily breakdown")
34
+
35
+
36
+ class UsageStatsResponse(BaseModel):
37
+ """Usage statistics response."""
38
+
39
+ current_month: CurrentUsageResponse
40
+ plan_name: str
41
+ plan_tier: str
42
+ rate_limit_per_minute: int
43
+ monthly_quota: int
44
+
45
+
46
+ class UsageWindowResponse(BaseModel):
47
+ """Usage window response for a specific time period."""
48
+
49
+ total_requests: int = Field(..., description="Total number of requests")
50
+ completed_tasks: int = Field(..., description="Number of completed tasks")
51
+ failed_tasks: int = Field(..., description="Number of failed tasks")
52
+
53
+
54
+ class DetailedUsageResponse(BaseModel):
55
+ """Detailed usage statistics response from Redis cache."""
56
+
57
+ period_start: datetime = Field(..., description="Start of the current billing period")
58
+ last_minute: UsageWindowResponse = Field(..., description="Usage in the last minute")
59
+ last_hour: UsageWindowResponse = Field(..., description="Usage in the last hour")
60
+ last_day: UsageWindowResponse = Field(..., description="Usage in the last day")
61
+ current_period: UsageWindowResponse = Field(
62
+ ..., description="Usage in the current billing period"
63
+ )
64
+ plan: str = Field(..., description="Current plan tier (free/pro/enterprise)")
65
+ monthly_quota: int = Field(..., description="Monthly quota limit for the plan")
66
+ requests_per_minute: int = Field(..., description="Rate limit per minute")
67
+ remaining_quota: int = Field(..., description="Remaining quota for the current period")
68
+ quota_percentage_used: float = Field(
69
+ ..., description="Percentage of monthly quota used (0-100)"
70
+ )
71
+ last_updated: datetime = Field(..., description="When this data was last calculated")
@@ -0,0 +1,34 @@
1
+ """Broker-related models and configuration."""
2
+
3
+ from tradepose_models.broker.account_config import (
4
+ AccountStatus,
5
+ BrokerAccount,
6
+ BrokerCredentials,
7
+ MarketType,
8
+ )
9
+ from tradepose_models.broker.account_models import (
10
+ AccountBalance,
11
+ AccountInfo,
12
+ MarginInfo,
13
+ )
14
+ from tradepose_models.broker.binding import AccountPortfolioBinding
15
+ from tradepose_models.broker.connection_status import ConnectionStatus
16
+ from tradepose_models.enums import BrokerType
17
+
18
+ __all__ = [
19
+ # Enums
20
+ "BrokerType",
21
+ "MarketType",
22
+ "AccountStatus",
23
+ "ConnectionStatus",
24
+ # Credentials
25
+ "BrokerCredentials",
26
+ # Account
27
+ "BrokerAccount",
28
+ # Account Info
29
+ "AccountBalance",
30
+ "AccountInfo",
31
+ "MarginInfo",
32
+ # Binding
33
+ "AccountPortfolioBinding",
34
+ ]
@@ -0,0 +1,93 @@
1
+ """Broker account configuration models."""
2
+
3
+ from datetime import datetime
4
+ from enum import Enum
5
+ from typing import Any, Optional
6
+ from uuid import UUID
7
+
8
+ from pydantic import BaseModel, Field, SecretStr
9
+
10
+ from tradepose_models.enums import AccountSource, BrokerType
11
+
12
+
13
+ class MarketType(str, Enum):
14
+ """Market types."""
15
+
16
+ SPOT = "spot" # Spot market
17
+ FUTURES = "futures" # Futures
18
+ MARGIN = "margin" # Margin trading
19
+ OPTIONS = "options" # Options
20
+ SWAP = "swap" # Perpetual swap
21
+
22
+
23
+ class AccountStatus(str, Enum):
24
+ """Account status."""
25
+
26
+ ACTIVE = "active"
27
+ INACTIVE = "inactive"
28
+ SUSPENDED = "suspended"
29
+ EXPIRED = "expired"
30
+
31
+
32
+ class BrokerCredentials(BaseModel):
33
+ """
34
+ Broker credentials (encrypted storage).
35
+
36
+ Credentials are provided by users and passed to adapters.
37
+ Storage encryption is handled by consuming applications.
38
+ """
39
+
40
+ api_key: SecretStr = Field(..., description="API Key")
41
+ api_secret: SecretStr = Field(..., description="API Secret")
42
+
43
+ # Optional fields (broker-specific)
44
+ passphrase: Optional[SecretStr] = Field(None, description="API Passphrase (OKX)")
45
+ account_id: Optional[str] = Field(None, description="Account ID")
46
+ password: Optional[SecretStr] = Field(None, description="Login password (MT5)")
47
+ person_id: Optional[str] = Field(None, description="Person ID (Taiwan brokers)")
48
+
49
+ # Additional config
50
+ extra_config: dict[str, Any] = Field(default_factory=dict)
51
+
52
+
53
+ class BrokerAccount(BaseModel):
54
+ """
55
+ Broker account configuration.
56
+
57
+ This model is passed to BrokerAdapter on initialization.
58
+ It contains all information needed to connect to a broker.
59
+ """
60
+
61
+ # Basic info
62
+ id: UUID = Field(..., description="Account UUID")
63
+ user_id: UUID = Field(..., description="User UUID who owns this account")
64
+ name: str = Field(..., description="Account name")
65
+
66
+ # Broker info (immutable after creation)
67
+ broker_type: BrokerType = Field(..., description="Broker type")
68
+ credentials: BrokerCredentials = Field(..., description="Encrypted credentials")
69
+
70
+ # Market configuration
71
+ available_markets: list[MarketType] = Field(
72
+ ..., description="Supported market types for this account"
73
+ )
74
+ default_market: Optional[MarketType] = Field(None, description="Default market type")
75
+
76
+ # Environment configuration
77
+ environment: str = Field(
78
+ default="production", description="Environment (production/testnet/sandbox)"
79
+ )
80
+ base_url: Optional[str] = Field(None, description="API Base URL")
81
+ ws_url: Optional[str] = Field(None, description="WebSocket URL")
82
+
83
+ # Status
84
+ status: AccountStatus = Field(default=AccountStatus.INACTIVE)
85
+
86
+ # Account source (for timezone handling)
87
+ account_source: Optional[AccountSource] = Field(
88
+ None, description="Account source (FTMO, IB, etc.) for timezone determination"
89
+ )
90
+
91
+ # Metadata
92
+ created_at: datetime
93
+ updated_at: datetime
@@ -0,0 +1,61 @@
1
+ """Account balance and information models."""
2
+
3
+ from datetime import datetime
4
+ from decimal import Decimal
5
+ from typing import Optional
6
+ from uuid import UUID
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+
11
+ class AccountBalance(BaseModel):
12
+ """Account balance for a specific asset."""
13
+
14
+ asset: str = Field(..., description="Asset symbol (USD, USDT, BTC, etc.)")
15
+ total: Decimal = Field(..., description="Total balance")
16
+ free: Decimal = Field(..., description="Available balance")
17
+ locked: Decimal = Field(default=Decimal("0"), description="Locked balance in orders/margin")
18
+
19
+
20
+ class AccountInfo(BaseModel):
21
+ """Account information."""
22
+
23
+ # Basic identification
24
+ account_id: UUID = Field(..., description="Unique account identifier")
25
+ broker: str = Field(..., description="Broker name (mt5, binance, okx)")
26
+ account_type: str = Field(..., description="CASH, MARGIN, FUTURES, SPOT, demo, real")
27
+
28
+ # Status (provide defaults for backward compatibility)
29
+ status: str = Field(default="ACTIVE", description="ACTIVE, SUSPENDED, CLOSED")
30
+ trading_enabled: bool = Field(default=True)
31
+
32
+ # Financial information
33
+ total_equity: Decimal = Field(..., description="Total account equity")
34
+ available_balance: Decimal = Field(..., description="Available balance for trading")
35
+ used_margin: Decimal = Field(default=Decimal("0"), description="Margin currently in use")
36
+
37
+ # Account attributes
38
+ leverage: int = Field(default=1, description="Account leverage")
39
+ currency: str = Field(default="USD", description="Account base currency")
40
+ position_count: int = Field(default=0, description="Number of open positions")
41
+
42
+ # Timestamps
43
+ created_at: Optional[datetime] = None
44
+
45
+ # Extended fields for broker-specific info
46
+ broker: Optional[str] = Field(None, description="Broker name")
47
+ total_equity: Optional[Decimal] = Field(None, description="Total equity")
48
+ available_balance: Optional[Decimal] = Field(None, description="Available balance")
49
+ used_margin: Optional[Decimal] = Field(None, description="Used margin")
50
+ position_count: Optional[int] = Field(None, description="Number of open positions")
51
+ leverage: Optional[int] = Field(None, description="Account leverage")
52
+ currency: Optional[str] = Field(None, description="Account currency")
53
+
54
+
55
+ class MarginInfo(BaseModel):
56
+ """Margin information."""
57
+
58
+ initial_margin: Decimal = Field(..., description="Initial margin requirement")
59
+ maintenance_margin: Decimal = Field(..., description="Maintenance margin requirement")
60
+ margin_level: Decimal = Field(..., description="Margin level (%)")
61
+ liquidation_price: Optional[Decimal] = Field(None, description="Liquidation price")
@@ -0,0 +1,54 @@
1
+ """
2
+ Account-Portfolio Binding Model
3
+
4
+ Provides the AccountPortfolioBinding model for linking trading accounts to portfolios.
5
+ """
6
+
7
+ from datetime import datetime
8
+ from decimal import Decimal
9
+ from typing import Optional
10
+ from uuid import UUID
11
+
12
+ from pydantic import BaseModel, Field
13
+
14
+ from ..enums import ExecutionMode
15
+
16
+
17
+ class AccountPortfolioBinding(BaseModel):
18
+ """Account-Portfolio binding configuration.
19
+
20
+ Links a trading account to a portfolio for automated trading.
21
+ Controls execution behavior and capital allocation.
22
+
23
+ Unique constraint: (account_id, portfolio_id)
24
+ """
25
+
26
+ id: UUID = Field(..., description="Binding UUID (primary key)")
27
+ user_id: UUID = Field(..., description="User UUID for multi-tenancy")
28
+ account_id: UUID = Field(..., description="Trading account UUID (FK)")
29
+ portfolio_id: UUID = Field(..., description="Portfolio UUID (FK)")
30
+ is_active: bool = Field(default=True, description="Whether binding is active")
31
+
32
+ capital_override: Optional[Decimal] = Field(
33
+ None, description="Override portfolio capital for this binding"
34
+ )
35
+ execution_mode: ExecutionMode = Field(
36
+ default=ExecutionMode.PRICE_PRIORITY,
37
+ description="Execution mode (price_priority or signal_priority)",
38
+ )
39
+ order_split_config: Optional[dict] = Field(
40
+ None, description="Order split configuration (reserved for future use)"
41
+ )
42
+
43
+ created_at: datetime = Field(..., description="Creation timestamp")
44
+ updated_at: datetime = Field(..., description="Last update timestamp")
45
+
46
+ @property
47
+ def is_price_priority(self) -> bool:
48
+ """Check if execution mode is price priority."""
49
+ return self.execution_mode == ExecutionMode.PRICE_PRIORITY
50
+
51
+ @property
52
+ def is_signal_priority(self) -> bool:
53
+ """Check if execution mode is signal priority."""
54
+ return self.execution_mode == ExecutionMode.SIGNAL_PRIORITY
@@ -0,0 +1,14 @@
1
+ """Connection status enum for broker adapters."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class ConnectionStatus(str, Enum):
7
+ """Broker connection status states."""
8
+
9
+ DISCONNECTED = "disconnected"
10
+ CONNECTING = "connecting"
11
+ CONNECTED = "connected"
12
+ RECONNECTING = "reconnecting"
13
+ FAILED = "failed"
14
+ SCHEDULED_DOWNTIME = "scheduled_downtime"
@@ -0,0 +1,8 @@
1
+ """Trader command models (Issue #307).
2
+
3
+ Models for commands sent to Trader via Redis Streams.
4
+ """
5
+
6
+ from .trader_command import CommandType, TraderCommand
7
+
8
+ __all__ = ["CommandType", "TraderCommand"]