Crypto trading bot: engine, brokers, backtester, dashboard, deploy
FastAPI backend with a single-strategy async engine, paper and Binance brokers, pure-python indicators, a backtester that shares the engine's portfolio math, and a Vue dashboard with a live WebSocket feed. Adds the Gitea Actions CI/CD workflow that deploys to Traefik via docker_default.
This commit is contained in:
1 parent
98028248c2
commit
9c3bee87ac
73 files changed
+9759
-1
No files matched your search
@@ -0,0 +1,179 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class Candle(BaseModel):
|
||||
ts: int
|
||||
open: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
volume: float
|
||||
|
||||
|
||||
class ParamSpec(BaseModel):
|
||||
name: str
|
||||
type: Literal["int", "float", "bool", "str"]
|
||||
default: Any
|
||||
description: str = ""
|
||||
min: float | None = None
|
||||
max: float | None = None
|
||||
|
||||
|
||||
class StrategyOut(BaseModel):
|
||||
key: str
|
||||
name: str
|
||||
description: str
|
||||
params: list[ParamSpec]
|
||||
|
||||
|
||||
class PositionOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
strategy_key: str
|
||||
symbol: str
|
||||
side: str
|
||||
qty: float
|
||||
entry_price: float
|
||||
status: str
|
||||
stop_loss: float | None = None
|
||||
take_profit: float | None = None
|
||||
exit_price: float | None = None
|
||||
realized_pnl: float | None = None
|
||||
unrealized_pnl: float | None = None
|
||||
opened_at: datetime
|
||||
closed_at: datetime | None = None
|
||||
|
||||
|
||||
class OrderOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
position_id: int | None
|
||||
strategy_key: str
|
||||
symbol: str
|
||||
side: str
|
||||
qty: float
|
||||
price: float
|
||||
fee: float
|
||||
reason: str
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class EventOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
level: str
|
||||
message: str
|
||||
strategy_key: str | None
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class EquityPointOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
equity: float
|
||||
cash: float
|
||||
price: float
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class StatusOut(BaseModel):
|
||||
running: bool
|
||||
mode: str
|
||||
exchange: str
|
||||
symbol: str
|
||||
timeframe: str
|
||||
strategy_key: str | None
|
||||
strategy_name: str | None
|
||||
params: dict[str, Any] = Field(default_factory=dict)
|
||||
price: float | None
|
||||
cash: float
|
||||
equity: float
|
||||
starting_balance: float
|
||||
realized_pnl: float
|
||||
unrealized_pnl: float
|
||||
total_pnl: float
|
||||
open_positions: int
|
||||
last_tick: datetime | None
|
||||
error: str | None = None
|
||||
|
||||
|
||||
class StartRequest(BaseModel):
|
||||
strategy_key: str
|
||||
symbol: str | None = None
|
||||
timeframe: str | None = None
|
||||
params: dict[str, Any] = Field(default_factory=dict)
|
||||
starting_balance: float | None = None
|
||||
|
||||
|
||||
class ManualOrderRequest(BaseModel):
|
||||
side: Literal["buy", "sell"]
|
||||
qty: float | None = None
|
||||
quote_amount: float | None = None
|
||||
reason: str = "manual"
|
||||
|
||||
|
||||
class ClosePositionRequest(BaseModel):
|
||||
reason: str = "manual"
|
||||
|
||||
|
||||
class BacktestRequest(BaseModel):
|
||||
strategy_key: str
|
||||
params: dict[str, Any] = Field(default_factory=dict)
|
||||
symbol: str | None = None
|
||||
timeframe: str | None = None
|
||||
limit: int = Field(default=500, ge=20, le=1000)
|
||||
starting_balance: float | None = None
|
||||
|
||||
|
||||
class BacktestTradeOut(BaseModel):
|
||||
side: str
|
||||
entry_ts: int
|
||||
exit_ts: int
|
||||
entry_price: float
|
||||
exit_price: float
|
||||
qty: float
|
||||
pnl: float
|
||||
return_pct: float
|
||||
reason: str
|
||||
|
||||
|
||||
class BacktestPointOut(BaseModel):
|
||||
ts: int
|
||||
equity: float
|
||||
buy_hold: float
|
||||
price: float
|
||||
|
||||
|
||||
class BacktestMetricsOut(BaseModel):
|
||||
initial_equity: float
|
||||
final_equity: float
|
||||
total_return_pct: float
|
||||
buy_hold_return_pct: float
|
||||
max_drawdown_pct: float
|
||||
num_trades: int
|
||||
win_rate_pct: float
|
||||
profit_factor: float | None
|
||||
avg_trade_pct: float
|
||||
best_trade_pct: float
|
||||
worst_trade_pct: float
|
||||
sharpe: float | None
|
||||
|
||||
|
||||
class BacktestResult(BaseModel):
|
||||
strategy_key: str
|
||||
strategy_name: str
|
||||
symbol: str
|
||||
timeframe: str
|
||||
starting_balance: float
|
||||
metrics: BacktestMetricsOut
|
||||
equity_curve: list[BacktestPointOut]
|
||||
trades: list[BacktestTradeOut]
|
||||
error: str | None = None
|
||||
Reference in new issue
Block a user