This commit is contained in:
+21
-14
@@ -31,20 +31,23 @@ type ManagerConfig struct {
|
||||
}
|
||||
|
||||
type PreTradeInput struct {
|
||||
Portfolio domain.Portfolio
|
||||
OpenPositions int
|
||||
ClosingPosition bool
|
||||
DailyPnL decimal.Decimal
|
||||
WeeklyPnL decimal.Decimal
|
||||
MonthlyDrawdownPct decimal.Decimal
|
||||
AvgSlippageBps10 decimal.Decimal
|
||||
TradingStatus domain.TradingStatus
|
||||
QuoteReceivedAt time.Time
|
||||
Now time.Time
|
||||
MarketClose time.Time
|
||||
DatabaseUnavailable bool
|
||||
UnknownBrokerOrder bool
|
||||
UnknownBrokerHolding bool
|
||||
Portfolio domain.Portfolio
|
||||
OpenPositions int
|
||||
ClosingPosition bool
|
||||
DailyPnL decimal.Decimal
|
||||
WeeklyPnL decimal.Decimal
|
||||
MonthlyDrawdownPct decimal.Decimal
|
||||
AvgSlippageBps10 decimal.Decimal
|
||||
TradingStatus domain.TradingStatus
|
||||
QuoteReceivedAt time.Time
|
||||
Now time.Time
|
||||
MarketClose time.Time
|
||||
ServerTimeUnavailable bool
|
||||
ServerClockDrift time.Duration
|
||||
MaxClockDrift time.Duration
|
||||
DatabaseUnavailable bool
|
||||
UnknownBrokerOrder bool
|
||||
UnknownBrokerHolding bool
|
||||
}
|
||||
|
||||
type PreTradeResult struct {
|
||||
@@ -84,6 +87,10 @@ func (m Manager) PreTradeCheck(input PreTradeInput) PreTradeResult {
|
||||
switch {
|
||||
case input.DatabaseUnavailable:
|
||||
return reject("database_unavailable")
|
||||
case input.ServerTimeUnavailable:
|
||||
return reject("server_time_unavailable")
|
||||
case input.MaxClockDrift > 0 && input.ServerClockDrift > input.MaxClockDrift:
|
||||
return reject("server_clock_drift_too_high")
|
||||
case input.UnknownBrokerOrder:
|
||||
return reject("unknown_broker_order")
|
||||
case input.UnknownBrokerHolding:
|
||||
|
||||
@@ -2,6 +2,7 @@ package risk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
|
||||
@@ -26,3 +27,30 @@ func TestPreTradeClosingPositionBypassesOpenPositionLimit(t *testing.T) {
|
||||
t.Fatalf("entry result=%+v, want max_open_positions reject", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreTradeRejectsServerClockDrift(t *testing.T) {
|
||||
manager := NewManager(nil, ManagerConfig{})
|
||||
input := PreTradeInput{
|
||||
Portfolio: domain.Portfolio{Equity: decimal.NewFromInt(1000)},
|
||||
TradingStatus: domain.TradingStatusNormal,
|
||||
ServerClockDrift: 3 * time.Second,
|
||||
MaxClockDrift: 2 * time.Second,
|
||||
}
|
||||
result := manager.PreTradeCheck(input)
|
||||
if result.Allowed || result.Reason != "server_clock_drift_too_high" {
|
||||
t.Fatalf("result=%+v, want server_clock_drift_too_high reject", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreTradeRejectsUnavailableServerTime(t *testing.T) {
|
||||
manager := NewManager(nil, ManagerConfig{})
|
||||
input := PreTradeInput{
|
||||
Portfolio: domain.Portfolio{Equity: decimal.NewFromInt(1000)},
|
||||
TradingStatus: domain.TradingStatusNormal,
|
||||
ServerTimeUnavailable: true,
|
||||
}
|
||||
result := manager.PreTradeCheck(input)
|
||||
if result.Allowed || result.Reason != "server_time_unavailable" {
|
||||
t.Fatalf("result=%+v, want server_time_unavailable reject", result)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user