Хуки жизненного цикла стратегий
В этом разделе описан контракт lifecycle-хуков, который использует shared runtime стратегии.
Хуки можно объявлять в двух местах:
- локально для стратегии в
manifest.tsчерезmanifest.hooks - на уровне проекта в
tradejs.config.tsчерезhooks
Project-level hooks применяются ко всем стратегиям, которые загружены текущим config. Strategy hooks из manifest при этом не исчезают: они merge’ятся дополнительно. Для одного и того же stage сначала выполняются project hooks, потом hooks из manifest стратегии.
Порядок вызова
- onInit — один раз при создании runtime
- onBar — на каждой свече до
core.ts - afterCoreDecision — после
core.ts, только еслиcore.tsвообще выполнялся - afterBarDecision — после финального решения по свече, независимо от того, пришло оно из
onBarили изcore.ts - onSkip — только для
skip - beforeClosePosition — gate, может заблокировать закрытие
- afterEnrichMl — только когда есть
decision.signal - afterEnrichAi — только когда есть
decision.signal - beforeEntryGate — gate, может заблокировать вход
- beforePlaceOrder — прямо перед вызовом коннектора
- afterPlaceOrder — после успешной постановки ордера
- onRuntimeError — на любой runtime/hook error
Канонический shape params
Теперь каждый хук получает stage-specific подмножество одного и того же вложенного объекта:
{
ctx?: StrategyHookCtx;
market?: StrategyHookMarketContext;
decision?: StrategyDecision;
entry?: StrategyHookEntryContext;
ml?: StrategyHookMlContext;
ai?: StrategyHookAiContext;
policy?: StrategyHookPolicyContext;
order?: StrategyHookOrderContext;
error?: StrategyHookErrorPayload;
}
Общие вложенные объекты
ctx:
{
connector: Connector;
strategyName: string;
userName: string;
symbol: string;
strategyConfig: StrategyConfig;
env: string;
isConfigFromBacktest: boolean;
}
market:
{
candle?: KlineChartItem;
btcCandle?: KlineChartItem;
data?: KlineChartItem[];
btcData?: KlineChartItem[];
}
entry:
{
context: StrategyEntrySignalContext;
orderPlan: StrategyEntryOrderPlan;
signal?: Signal;
runtime: {
raw?: StrategyEntryRuntimeOptions;
resolved: StrategyEntryRuntimeOptions;
};
}
ml:
{
config?: StrategyRuntimeMlOptions;
attempted: boolean;
applied: boolean;
result?: Signal['ml'];
skippedReason?:
| 'BACKTEST'
| 'DISABLED'
| 'NO_RUNTIME'
| 'NO_STRATEGY_CONFIG'
| 'NO_THRESHOLD'
| 'NO_RESULT';
}
ai:
{
config?: StrategyRuntimeAiOptions;
attempted: boolean;
applied: boolean;
quality?: number;
skippedReason?: 'BACKTEST' | 'DISABLED' | 'NO_RUNTIME' | 'NO_QUALITY';
}
policy:
{
aiQuality?: number;
makeOrdersEnabled: boolean;
minAiQuality: number;
}
order:
{
result: Signal | string;
}
error:
{
stage: StrategyHookStage;
cause: unknown;
}
Gate-хуки возвращают такой shape, если хотят заблокировать исполнение:
{
allow?: boolean;
reason?: string;
}
Важные замечания
- Используйте
tradejs.config.ts -> hooks, когда логика должна применяться сразу ко всем стратегиям проекта: например, для общих risk rules, cross-strategy управления позициями или общих фильтров на постановку ордеров. beforeSignalsиafterSignalsтоже являются project-level hooks вtradejs.config.ts, но относятся к lifecycle командыsignals, а не к per-strategy runtime, который описан на этой странице.- Логику, которая нужна только одной стратегии, оставляйте в
manifest.hooks. entry.runtime.raw— это raw runtime, который вернулcore.tsчерезstrategyApi.entry(...).entry.runtime.resolved— это runtime, который реально использует shared runtime после merge manifest defaults, adapter config и raw decision runtime.afterEnrichMlописывает именно ML stage, а не только успешный ML. Смотриml.attempted,ml.appliedиml.skippedReason.afterEnrichAiиспользует тот же паттерн через объектai.afterCoreDecisionтеперь строго post-core.ts. Если свеча была short-circuit’нута вonBar, а тебе все равно нужно увидеть итоговое решение по свече, используйafterBarDecision.- Ошибки non-blocking хуков проглатываются: runtime логирует их, вызывает
onRuntimeErrorи продолжает выполнение. - Ошибки в gate-хуках (
beforeClosePosition,beforeEntryGate) тоже проглатываются; runtime ведет себя так, будто хук вернулundefined.