feat(engine): 新增 Python 策略引擎模块
- config/settings.py:Pydantic 解析 env.yaml - data/db.py:asyncpg 连接池管理 - data/reader.py:KlineReader 只读查询 TimescaleDB - data/models.py:KlineRecord 等 Pydantic 模型,镜像 TypeORM 实体 - example/test_db.py:数据库查询验证示例 - README.md:引擎架构文档
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Python 数据模型 —— 镜像 data/db/entities/ 中的 TypeORM 实体。
|
||||
|
||||
命名约定:
|
||||
- 类名与 TypeORM 实体类名一致(Kline, Exchange, TradingPair)
|
||||
- 字段名使用 Python snake_case,对应 TypeORM 的 camelCase / snake_case
|
||||
- 所有模型使用 Pydantic,提供运行时校验 + IDE 智能提示
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class KlineRecord(BaseModel):
|
||||
"""
|
||||
K 线数据记录。
|
||||
|
||||
映射关系:
|
||||
TypeORM Kline.time → KlineRecord.time
|
||||
TypeORM Kline.exchange → KlineRecord.exchange
|
||||
TypeORM Kline.symbol → KlineRecord.symbol
|
||||
TypeORM Kline.interval → KlineRecord.interval
|
||||
TypeORM Kline.open → KlineRecord.open
|
||||
TypeORM Kline.high → KlineRecord.high
|
||||
TypeORM Kline.low → KlineRecord.low
|
||||
TypeORM Kline.close → KlineRecord.close
|
||||
TypeORM Kline.volume → KlineRecord.volume
|
||||
TypeORM Kline.quote_volume → KlineRecord.quote_volume
|
||||
TypeORM Kline.taker_buy_base_vol → KlineRecord.taker_buy_base_vol
|
||||
TypeORM Kline.taker_buy_quote_vol→ KlineRecord.taker_buy_quote_vol
|
||||
TypeORM Kline.trade_count → KlineRecord.trade_count
|
||||
TypeORM Kline.is_closed → KlineRecord.is_closed
|
||||
"""
|
||||
|
||||
time: datetime
|
||||
exchange: str
|
||||
symbol: str
|
||||
interval: str
|
||||
|
||||
open: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
volume: float
|
||||
|
||||
quote_volume: Optional[float] = None
|
||||
taker_buy_base_vol: Optional[float] = None
|
||||
taker_buy_quote_vol: Optional[float] = None
|
||||
trade_count: Optional[int] = None
|
||||
is_closed: bool = True
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
@classmethod
|
||||
def from_record(cls, record) -> "KlineRecord":
|
||||
return cls(
|
||||
time=record["time"],
|
||||
exchange=record["exchange"],
|
||||
symbol=record["symbol"],
|
||||
interval=record["interval"],
|
||||
open=float(record["open"]),
|
||||
high=float(record["high"]),
|
||||
low=float(record["low"]),
|
||||
close=float(record["close"]),
|
||||
volume=float(record["volume"]),
|
||||
quote_volume=float(record["quote_volume"]) if record["quote_volume"] is not None else None,
|
||||
taker_buy_base_vol=float(record["taker_buy_base_vol"]) if record["taker_buy_base_vol"] is not None else None,
|
||||
taker_buy_quote_vol=float(record["taker_buy_quote_vol"]) if record["taker_buy_quote_vol"] is not None else None,
|
||||
trade_count=int(record["trade_count"]) if record["trade_count"] is not None else None,
|
||||
is_closed=bool(record["is_closed"]),
|
||||
created_at=record["created_at"] if "created_at" in record else None,
|
||||
updated_at=record["updated_at"] if "updated_at" in record else None,
|
||||
)
|
||||
|
||||
|
||||
class TradingPairInfo(BaseModel):
|
||||
"""交易对配置信息(轻量版,仅包含策略决策所需的字段)"""
|
||||
|
||||
symbol: str
|
||||
exchange: str
|
||||
base_asset: str
|
||||
quote_asset: str
|
||||
price_precision: int
|
||||
quantity_precision: int
|
||||
min_qty: Optional[float] = None
|
||||
min_notional: Optional[float] = None
|
||||
active: bool = True
|
||||
|
||||
|
||||
class Signal(BaseModel):
|
||||
"""交易信号"""
|
||||
|
||||
symbol: str
|
||||
signal_type: str = Field(..., pattern=r"^(BUY|SELL|HOLD)$")
|
||||
price: Optional[float] = None
|
||||
quantity: Optional[float] = None
|
||||
reason: str = ""
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
Reference in New Issue
Block a user