Files
overnight-trading-bot/internal/domain/types.go
T

312 lines
7.7 KiB
Go
Raw Normal View History

2026-06-07 21:01:40 +00:00
package domain
import (
"fmt"
"strings"
"time"
"github.com/shopspring/decimal"
)
type Mode string
const (
ModeBacktest Mode = "backtest"
ModePaper Mode = "paper"
ModeSandbox Mode = "sandbox"
ModeLiveReadonly Mode = "live_readonly"
ModeLiveTrade Mode = "live_trade"
)
func ParseMode(raw string) (Mode, error) {
mode := Mode(strings.TrimSpace(raw))
switch mode {
case ModeBacktest, ModePaper, ModeSandbox, ModeLiveReadonly, ModeLiveTrade:
return mode, nil
default:
return "", fmt.Errorf("unsupported app mode %q", raw)
}
}
func (m Mode) AllowsBrokerOrders() bool {
return m == ModeSandbox || m == ModeLiveTrade
}
func (m *Mode) UnmarshalText(text []byte) error {
mode, err := ParseMode(string(text))
if err != nil {
return err
}
*m = mode
return nil
}
type Side string
const (
SideBuy Side = "BUY"
SideSell Side = "SELL"
)
type OrderType string
const (
OrderTypeLimit OrderType = "LIMIT"
)
type OrderStatus string
const (
OrderStatusNew OrderStatus = "NEW"
OrderStatusSent OrderStatus = "SENT"
OrderStatusPartiallyFilled OrderStatus = "PARTIALLY_FILLED"
OrderStatusFilled OrderStatus = "FILLED"
OrderStatusCancelled OrderStatus = "CANCELLED"
OrderStatusRejected OrderStatus = "REJECTED"
OrderStatusExpired OrderStatus = "EXPIRED"
OrderStatusFailed OrderStatus = "FAILED"
)
type SignalDecision string
const (
DecisionEnter SignalDecision = "ENTER"
DecisionSkip SignalDecision = "SKIP"
DecisionReject SignalDecision = "REJECT"
)
type PositionStatus string
const (
PositionNoPosition PositionStatus = "NO_POSITION"
PositionEntrySignalled PositionStatus = "ENTRY_SIGNALLED"
PositionEntryOrderSent PositionStatus = "ENTRY_ORDER_SENT"
PositionEntryPartiallyFilled PositionStatus = "ENTRY_PARTIALLY_FILLED"
PositionEntryFilled PositionStatus = "ENTRY_FILLED"
PositionHoldingOvernight PositionStatus = "HOLDING_OVERNIGHT"
PositionExitOrderSent PositionStatus = "EXIT_ORDER_SENT"
PositionExitPartiallyFilled PositionStatus = "EXIT_PARTIALLY_FILLED"
PositionExitFilled PositionStatus = "EXIT_FILLED"
PositionExitFailed PositionStatus = "EXIT_FAILED"
PositionQuarantine PositionStatus = "QUARANTINE"
)
type SystemState string
const (
StateInit SystemState = "INIT"
StateSyncInstruments SystemState = "SYNC_INSTRUMENTS"
StateSyncMarketData SystemState = "SYNC_MARKET_DATA"
StateGenerateSignals SystemState = "GENERATE_SIGNALS"
StateWaitEntryWindow SystemState = "WAIT_ENTRY_WINDOW"
StatePlaceEntryOrders SystemState = "PLACE_ENTRY_ORDERS"
StateMonitorEntryOrders SystemState = "MONITOR_ENTRY_ORDERS"
StateHoldOvernight SystemState = "HOLD_OVERNIGHT"
StateWaitExitWindow SystemState = "WAIT_EXIT_WINDOW"
StatePlaceExitOrders SystemState = "PLACE_EXIT_ORDERS"
StateMonitorExitOrders SystemState = "MONITOR_EXIT_ORDERS"
StateReconcile SystemState = "RECONCILE"
StateReport SystemState = "REPORT"
StateSleep SystemState = "SLEEP"
StateHalted SystemState = "HALTED"
)
type Severity string
const (
SeverityInfo Severity = "INFO"
SeverityWarn Severity = "WARN"
SeverityAlert Severity = "ALERT"
SeverityCritical Severity = "CRITICAL"
)
type TradingStatus string
const (
TradingStatusNormal TradingStatus = "NORMAL_TRADING"
TradingStatusClosed TradingStatus = "CLOSED"
TradingStatusUnknown TradingStatus = "UNKNOWN"
)
type Instrument struct {
InstrumentUID string
Figi string
Ticker string
ClassCode string
Name string
Lot int64
MinPriceIncrement decimal.Decimal
Currency string
Enabled bool
FundType string
ExpectedCommissionBpsPerSide decimal.Decimal
FreeOrderLimitPerDay int
Quarantine bool
QuarantineReason string
ExcludeReason string
UpdatedAt time.Time
}
func (i Instrument) MetadataValid() bool {
return i.InstrumentUID != "" &&
!strings.HasPrefix(i.InstrumentUID, "PENDING:") &&
i.Lot > 0 &&
i.MinPriceIncrement.IsPositive() &&
strings.EqualFold(i.Currency, "RUB")
}
type Candle struct {
InstrumentUID string
TradeDate time.Time
Open decimal.Decimal
High decimal.Decimal
Low decimal.Decimal
Close decimal.Decimal
VolumeLots decimal.Decimal
Source string
LoadedAt time.Time
}
type FeatureSet struct {
InstrumentUID string
TradeDate time.Time
ROn decimal.Decimal
RDay decimal.Decimal
MuOn60 decimal.Decimal
MuOn252 decimal.Decimal
SigmaOn60 decimal.Decimal
TStatOn60 decimal.Decimal
WinOn60 decimal.Decimal
EWMAOn decimal.Decimal
SpreadBps decimal.Decimal
HalfSpreadBps decimal.Decimal
TickBps decimal.Decimal
ADV20 decimal.Decimal
ExpectedCostBps decimal.Decimal
NetEdgeBps decimal.Decimal
EntryIntervalVolume decimal.Decimal
ExitIntervalVolume decimal.Decimal
CalculatedAt time.Time
}
type Signal struct {
ID int64
TradeDate time.Time
InstrumentUID string
Decision SignalDecision
Score decimal.Decimal
NetEdgeBps decimal.Decimal
TargetNotional decimal.Decimal
TargetLots int64
RejectReason string
ContextJSON string
CreatedAt time.Time
}
type Order struct {
ClientOrderID string
BrokerOrderID string
AccountIDHash string
InstrumentUID string
TradeDate time.Time
Side Side
OrderType OrderType
LimitPrice decimal.Decimal
QuantityLots int64
FilledLots int64
AvgFillPrice decimal.Decimal
Status OrderStatus
Commission decimal.Decimal
AttemptNo int
RawStateJSON string
CreatedAt time.Time
UpdatedAt time.Time
}
type Position struct {
ID int64
AccountIDHash string
InstrumentUID string
OpenTradeDate time.Time
Lots int64
Lot int64
ExitFilledLots int64
AvgBuyPrice decimal.Decimal
AvgSellPrice decimal.Decimal
Status PositionStatus
GrossPnL decimal.Decimal
NetPnL decimal.Decimal
CommissionTotal decimal.Decimal
RealizedEdgeBps decimal.Decimal
OpenedAt *time.Time
ClosedAt *time.Time
UpdatedAt time.Time
}
type RiskEvent struct {
ID int64
TS time.Time
Severity Severity
EventType string
InstrumentUID string
Message string
ContextJSON string
}
type Holding struct {
InstrumentUID string
QuantityLots int64
AveragePrice decimal.Decimal
MarketValue decimal.Decimal
}
type Portfolio struct {
Equity decimal.Decimal
Cash decimal.Decimal
Holdings []Holding
CheckedAt time.Time
}
type OrderBookLevel struct {
Price decimal.Decimal
QuantityLots int64
}
type OrderBook struct {
InstrumentUID string
Bids []OrderBookLevel
Asks []OrderBookLevel
Time time.Time
ReceivedAt time.Time
}
func (o OrderBook) BestBid() (decimal.Decimal, bool) {
if len(o.Bids) == 0 {
return decimal.Zero, false
}
return o.Bids[0].Price, true
}
func (o OrderBook) BestAsk() (decimal.Decimal, bool) {
if len(o.Asks) == 0 {
return decimal.Zero, false
}
return o.Asks[0].Price, true
}
type Operation struct {
ID string
InstrumentUID string
Type string
Payment decimal.Decimal
Commission decimal.Decimal
ExecutedAt time.Time
}
type ReconciliationDiff struct {
Kind string
InstrumentUID string
Message string
Critical bool
}