174 lines
3.7 KiB
Python
174 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
from enum import StrEnum
|
|
|
|
|
|
class TradeSide(StrEnum):
|
|
BUY = "buy"
|
|
SELL = "sell"
|
|
|
|
|
|
class TradeGroup(StrEnum):
|
|
BASE = "base"
|
|
GRID = "grid"
|
|
OTHER = "other"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Account:
|
|
id: int | None
|
|
name: str
|
|
initial_cash: Decimal
|
|
notes: str = ""
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Instrument:
|
|
id: int | None
|
|
code: str
|
|
name: str
|
|
market: str = "A"
|
|
lot_size: int = 100
|
|
manual_price: Decimal | None = None
|
|
allow_odd_lot: bool = False
|
|
active: bool = True
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class StrategyTemplate:
|
|
id: int | None
|
|
name: str
|
|
grid_spacing_pct: Decimal
|
|
amount_per_grid: Decimal
|
|
base_target_amount: Decimal
|
|
max_position_amount: Decimal
|
|
min_lot: int = 100
|
|
is_default: bool = False
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class StrategyOverride:
|
|
instrument_id: int
|
|
template_id: int | None = None
|
|
grid_spacing_pct: Decimal | None = None
|
|
amount_per_grid: Decimal | None = None
|
|
base_target_amount: Decimal | None = None
|
|
max_position_amount: Decimal | None = None
|
|
min_lot: int | None = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Trade:
|
|
id: int | None
|
|
account_id: int
|
|
instrument_id: int
|
|
trade_date: date
|
|
side: TradeSide
|
|
price: Decimal
|
|
quantity: int
|
|
commission: Decimal = Decimal("0")
|
|
stamp_tax: Decimal = Decimal("0")
|
|
transfer_fee: Decimal = Decimal("0")
|
|
trade_group: TradeGroup = TradeGroup.GRID
|
|
notes: str = ""
|
|
|
|
@property
|
|
def gross_amount(self) -> Decimal:
|
|
return self.price * Decimal(self.quantity)
|
|
|
|
@property
|
|
def total_fee(self) -> Decimal:
|
|
return self.commission + self.stamp_tax + self.transfer_fee
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class CashLedgerEntry:
|
|
id: int | None
|
|
account_id: int
|
|
entry_date: date
|
|
amount: Decimal
|
|
category: str
|
|
instrument_id: int | None = None
|
|
notes: str = ""
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class FeeRules:
|
|
commission_rate: Decimal
|
|
min_commission: Decimal
|
|
stamp_tax_rate: Decimal
|
|
transfer_fee_rate: Decimal
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class FeeEstimate:
|
|
commission: Decimal
|
|
stamp_tax: Decimal
|
|
transfer_fee: Decimal
|
|
|
|
@property
|
|
def total(self) -> Decimal:
|
|
return self.commission + self.stamp_tax + self.transfer_fee
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GridLevelSuggestion:
|
|
level: int
|
|
buy_price: Decimal
|
|
buy_amount: Decimal
|
|
suggested_quantity: int
|
|
actual_investment: Decimal
|
|
sell_price: Decimal
|
|
estimated_gross_profit: Decimal
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class QuoteSnapshot:
|
|
symbol: str
|
|
code: str
|
|
name: str
|
|
price: Decimal
|
|
source: str
|
|
quote_time: str | None = None
|
|
previous_close: Decimal | None = None
|
|
open_price: Decimal | None = None
|
|
high: Decimal | None = None
|
|
low: Decimal | None = None
|
|
change: Decimal | None = None
|
|
change_percent: Decimal | None = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PositionSummary:
|
|
instrument_id: int
|
|
code: str
|
|
name: str
|
|
market: str
|
|
current_price: Decimal | None
|
|
price_source: str
|
|
total_quantity: int
|
|
available_quantity: int
|
|
base_quantity: int
|
|
grid_quantity: int
|
|
other_quantity: int
|
|
remaining_cost: Decimal
|
|
cost_price: Decimal | None
|
|
position_breakeven_price: Decimal | None
|
|
account_breakeven_price: Decimal | None
|
|
realized_pnl: Decimal
|
|
grid_profit: Decimal
|
|
floating_pnl: Decimal | None
|
|
market_value: Decimal | None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AccountSummary:
|
|
total_assets: Decimal
|
|
cash: Decimal
|
|
market_value: Decimal
|
|
floating_pnl: Decimal
|
|
capital_usage_rate: Decimal
|