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.
- tradepose_models/__init__.py +44 -0
- tradepose_models/auth/__init__.py +13 -0
- tradepose_models/auth/api_keys.py +52 -0
- tradepose_models/auth/auth.py +20 -0
- tradepose_models/base.py +57 -0
- tradepose_models/billing/__init__.py +33 -0
- tradepose_models/billing/checkout.py +17 -0
- tradepose_models/billing/plans.py +32 -0
- tradepose_models/billing/subscriptions.py +34 -0
- tradepose_models/billing/usage.py +71 -0
- tradepose_models/broker/__init__.py +34 -0
- tradepose_models/broker/account_config.py +93 -0
- tradepose_models/broker/account_models.py +61 -0
- tradepose_models/broker/binding.py +54 -0
- tradepose_models/broker/connection_status.py +14 -0
- tradepose_models/commands/__init__.py +8 -0
- tradepose_models/commands/trader_command.py +80 -0
- tradepose_models/datafeed/__init__.py +19 -0
- tradepose_models/datafeed/events.py +132 -0
- tradepose_models/enums/__init__.py +47 -0
- tradepose_models/enums/account_source.py +42 -0
- tradepose_models/enums/broker_type.py +21 -0
- tradepose_models/enums/currency.py +17 -0
- tradepose_models/enums/engagement_phase.py +47 -0
- tradepose_models/enums/execution_mode.py +16 -0
- tradepose_models/enums/export_type.py +23 -0
- tradepose_models/enums/freq.py +32 -0
- tradepose_models/enums/indicator_type.py +46 -0
- tradepose_models/enums/operation_type.py +19 -0
- tradepose_models/enums/order_strategy.py +47 -0
- tradepose_models/enums/orderbook_event_type.py +29 -0
- tradepose_models/enums/persist_mode.py +28 -0
- tradepose_models/enums/stream.py +14 -0
- tradepose_models/enums/task_status.py +23 -0
- tradepose_models/enums/trade_direction.py +42 -0
- tradepose_models/enums/trend_type.py +22 -0
- tradepose_models/enums/weekday.py +30 -0
- tradepose_models/enums.py +32 -0
- tradepose_models/events/__init__.py +11 -0
- tradepose_models/events/order_events.py +79 -0
- tradepose_models/export/__init__.py +19 -0
- tradepose_models/export/request.py +52 -0
- tradepose_models/export/requests.py +75 -0
- tradepose_models/export/task_metadata.py +97 -0
- tradepose_models/gateway/__init__.py +19 -0
- tradepose_models/gateway/responses.py +37 -0
- tradepose_models/indicators/__init__.py +56 -0
- tradepose_models/indicators/base.py +42 -0
- tradepose_models/indicators/factory.py +254 -0
- tradepose_models/indicators/market_profile.md +60 -0
- tradepose_models/indicators/market_profile.py +333 -0
- tradepose_models/indicators/market_profile_developer.md +1782 -0
- tradepose_models/indicators/market_profile_trading.md +1060 -0
- tradepose_models/indicators/momentum.py +53 -0
- tradepose_models/indicators/moving_average.py +63 -0
- tradepose_models/indicators/other.py +40 -0
- tradepose_models/indicators/trend.py +80 -0
- tradepose_models/indicators/volatility.py +57 -0
- tradepose_models/instruments/__init__.py +13 -0
- tradepose_models/instruments/instrument.py +87 -0
- tradepose_models/scheduler/__init__.py +9 -0
- tradepose_models/scheduler/results.py +49 -0
- tradepose_models/schemas/__init__.py +15 -0
- tradepose_models/schemas/enhanced_ohlcv.py +111 -0
- tradepose_models/schemas/performance.py +40 -0
- tradepose_models/schemas/trades.py +64 -0
- tradepose_models/schemas.py +34 -0
- tradepose_models/shared.py +15 -0
- tradepose_models/strategy/__init__.py +52 -0
- tradepose_models/strategy/base.py +56 -0
- tradepose_models/strategy/blueprint.py +55 -0
- tradepose_models/strategy/config.py +142 -0
- tradepose_models/strategy/entities.py +104 -0
- tradepose_models/strategy/helpers.py +173 -0
- tradepose_models/strategy/indicator_spec.py +531 -0
- tradepose_models/strategy/performance.py +66 -0
- tradepose_models/strategy/portfolio.py +171 -0
- tradepose_models/strategy/registry.py +249 -0
- tradepose_models/strategy/requests.py +33 -0
- tradepose_models/strategy/trigger.py +77 -0
- tradepose_models/trading/__init__.py +55 -0
- tradepose_models/trading/engagement.py +160 -0
- tradepose_models/trading/orderbook.py +73 -0
- tradepose_models/trading/orders.py +137 -0
- tradepose_models/trading/positions.py +78 -0
- tradepose_models/trading/trader_commands.py +138 -0
- tradepose_models/trading/trades_execution.py +27 -0
- tradepose_models/types.py +35 -0
- tradepose_models/utils/__init__.py +13 -0
- tradepose_models/utils/rate_converter.py +112 -0
- tradepose_models/validators.py +32 -0
- tradepose_models-1.1.0.dist-info/METADATA +633 -0
- tradepose_models-1.1.0.dist-info/RECORD +94 -0
- 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
|
tradepose_models/base.py
ADDED
|
@@ -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"
|