Writing Custom Filters
Custom filters extend the Trade Director’s risk management capabilities.
The filter interface
Individual filters
type TradeDirectorFunc interface {
Name() string
Evaluate(ctx *DirectorContext, req *TradeRequest) (approved bool, reason string)
ParallelCompatible() bool
}Batch filters
type BatchTradeDirectorFunc interface {
Name() string
EvaluateBatch(ctx *BatchDirectorContext, requests []*TradeRequest) (
approved []*TradeRequest, rejections map[*TradeRequest]string)
ParallelCompatible() bool
}The TradeRequest
Each order generates a TradeRequest containing:
| Field | Type | Description |
|---|---|---|
StrategyID | string | Unique strategy identifier |
Symbol | string | Trading symbol |
OrderType | OrderType | Buy, Sell, ExitLong, ExitShort |
ExecMethod | OrderExecMethod | AtMarket, AtLimit, etc. |
Qty | int | Order quantity |
Price | float64 | Order price |
PointValue | float64 | Symbol’s point value |
AssetClass | AssetClass | Futures, Stock, etc. |
CategoryType | CategoryType | Energy, Metal, Index, etc. |
TDValue | any | Signal strength for ranking |
ParallelCompatible()
Return true if the filter only examines the trade request and does not need portfolio state. Return false if the filter reads portfolio-level fields like equity, exposure, or position counts.
Guidelines:
- Return
trueif your filter only examines the trade request and strategy-local data - Return
falseif your filter reads anyctx.Portfoliofields - Conditional compatibility: Some filters are parallel-compatible only in certain modes:
func (f *PositionSizer) ParallelCompatible() bool {
// Only parallel-compatible in "fixed" mode where no equity calculation needed
return f.Mode == "fixed"
}Example: time-of-day filter
type TimeOfDayFilter struct {
BlockedHours []int
}
func (f *TimeOfDayFilter) Name() string {
return "time-of-day"
}
func (f *TimeOfDayFilter) Evaluate(ctx *DirectorContext, req *TradeRequest) (bool, string) {
hour := time.Unix(req.Epoch, 0).UTC().Hour()
for _, blocked := range f.BlockedHours {
if hour == blocked {
return false, fmt.Sprintf("entries blocked during hour %d UTC", blocked)
}
}
return true, ""
}
func (f *TimeOfDayFilter) ParallelCompatible() bool {
return true // Does not access portfolio state
}