Каскаддык стратегиялар: Резерв менен толтуруу аркылуу приоритеттик аткаруу
«Иллюзиясыз бэктесттер» сериясынын финалы. N стратегия жана M жуп негизинде оркестраторду кантип куруу керек, приоритет жана резервдик аткаруусу бар каскаддык режимди ишке ашыруу, dual_size тандоо жана эмне үчүн стратегиялар портфелин жөн гана PnL кошуу аркылуу бэктестилөөгө болбойт.
Эмне үчүн стратегиялар портфели керек
Бир нече стратегия чектелген капитал үчүн атаандашат — алардын көбү бош турат, ар бир учурда болгону бир нечеси гана соода кылат
Сиз стратегияны толук конвейерден өткөрдүңүз. Монте-Карло бутстрап кабыл алынуучу 5-процентилди көрсөттү. Walk-forward үлгүдөн тышкаркы кирешелерди ырастады. Фандинг чендери эсептелди, плато анализи өттү. Стратегия чындап эле иштейт.
Бирок ал убакыттын 15%-ында гана соода кылат. Калган 85% убакытта сиздин капиталыңыз бош турат.
Экинчи стратегияны иштетүү керекпи? Үчүнчүсүн? Онунчусун? Идея айкын. Ишке ашыруу — жок. Стратегиялар портфели бир боттун өзүндө жок болгон көйгөйлөрдү жаратат:
- Конфликттер: эки стратегия бир жуп боюнча карама-каршы позицияларды ачкысы келет.
- Чектөөлөр: биржа/тобокелдик менеджмент бир убакытта ашпаган позицияларга гана уруксат берет.
- Бөлүштүрүү: ар бир стратегияга капиталдын кайсы бөлүгүн берүү керек?
- Корреляция: корреляцияланган крипто жуптарында 10 стратегия — бул 10 эсе диверсификация эмес.
Каскаддык стратегия — бул көйгөйлөрдү чечкен архитектуралык үлгү: негизги стратегия толук позиция көлөмүн алат, ал эми резервдик стратегия бош убакытты азайтылган позиция менен толтурат.
Каскад түшүнүгү: Негизги + Резерв

Жогорку ишенимдүүлүктөгү стратегия (Негизги)
Негизги — катуу кирүү критерийлери бар стратегия. Мисалы, үч ырастоочу деңгээли бар үч эселенген убакыт тилкеси: күндүзгү + 4 сааттык + сааттык сигнал, волатилдик жана көлөмдү чыпкалоо менен.
Мүнөздөмөлөрү:
- Аз бүтүмдөр (бэктест мезгилинде ондогон)
- Бүтүмгө жогорку PnL
- Позицияда болуу убактысы аз (5-15%)
- Ар бир киришке жогорку ишеним
Резервдик стратегия
Резерв — жеңилдетилген критерийлери бар стратегия. Кош убакыт тилкеси, аз чыпкалар, кеңири чектер. Ал көбүрөөк соода кылат, бирок бүтүмгө шаккан артыкчылыгы төмөн.
Мүнөздөмөлөрү:
- Көбүрөөк бүтүмдөр (мезгилде жүздөгөн)
- Бүтүмгө орточо PnL
- Позицияда болуу убактысы жогору (30-50%)
- Орточо ишеним — азайтылган позиция көлөмү менен компенсацияланат
Каскаддык режим
timeline: ──────────────────────────────────────────────────
primary: ___████___________________████████____███________
fallback: ███____███████████████████________████___████████
capital: [dual][ full ][ dual_size ][ full ][ dual ]
Негизги стратегия позиция ачканда — резерв унчукпай калат (же жабылат). Негизги бош турганда — резерв азайтылган позиция менен (dual_size) соода кылат. Приоритет шексиз: негизги ар дайым резервди ордунан кетирет.
Мисалдар үчүн стратегиялар
Серия боюнча биз үч стратегияны колдондук. Алардын 750 күндүк мезгилге арналган параметрлери:
| Параметр | Стратегия A | Стратегия B | Стратегия C |
|---|---|---|---|
| PnL | +55% | +27% | +300% |
| Бүтүмдөр | ~500 | ~40 | ~400 |
| Соода убактысы | ~15% | ~5% | ~45% |
| MaxDD | ~0.9% | ~0.75% | ~17% |
| Активдүү күнгө PnL | 0.49%/к | 0.72%/к | 0.89%/к |
| Мүнөзү | Орточо активдүүлүк | Сейрек, жогорку ишеним | Кыйла жиш, агрессивдүү |
Активдүү убакытка карата PnL макаласында көрсөткөндөй, чийки PnL боюнча жана активдүү күнгө PnL боюнча рейтинг ар башка натыйжаларды берет. Каскаддык оркестрация үчүн маанилүү болгону — экинчи көрсөткүч.
Оптималдуу dual_size
dual_size боюнча тор издөө Шарп коэффициентинин чокусун көрсөтөт — өтө чоңу просадканы жогорулатат, өтө кичинеси бош убакытты текке кетирет
Тандоо көйгөйү
dual_size — резервдик стратегия алган толук позициянын үлүшү. Бул негизги каскад параметри:
-
Өтө чоң (мисалы, 0.5 = 50%): негизги жана резерв бир учурда активдүү болгондо, жалпы экспозиция = максаттын 150%. Просадка эки эсе өсөт. Чыгым-пайда асимметриясы муну өтө кымбат кылат.
-
Өтө кичине (мисалы, 0.01 = 1%): резерв бош убакыттын 85%-ын толтурат, бирок тыйынды гана табат. Капитал иш жүзүндө бош турат.
-
Оптималдуу: резерв негизги менен бир учурда иштөө учурунда просадканы кризистик түрдө жогорулатпай туруп, маанилүү PnL кошот.
Формализация
Белгилейли:
- — негизги стратегиянын убакыт бирдигине PnL
- — резервдин убакыт бирдигине PnL
- — позицияда болуу убактысынын үлүшү (негизги)
- — позицияда болуу убактысынын үлүшү (резерв)
- — dual_size (0..1)
- — экөө тең позицияда болгон убакыттын үлүшү
Жалпы каскаддык PnL:
Жалпы MaxDD (эң начар учур — толук корреляция):
Эгер жалпы просадканы менен чектесек:
Тор издөө
Практикада оптималдуу dual_size каскаддык бэктестте тор издөө аркылуу табылат:
import numpy as np
from dataclasses import dataclass
@dataclass
class CascadeResult:
dual_size: float
total_pnl: float
max_dd: float
sharpe: float
pnl_per_active_day: float
def grid_search_dual_size(
primary_equity: np.ndarray, # equity curve primary (minute bars)
fallback_equity: np.ndarray, # equity curve fallback (minute bars)
primary_positions: np.ndarray, # 1 = in position, 0 = flat
fallback_positions: np.ndarray,
grid: np.ndarray = np.arange(0.01, 0.30, 0.005),
) -> list[CascadeResult]:
"""
Grid search for dual_size.
primary_equity and fallback_equity are log-returns, minute bars.
"""
results = []
for d in grid:
fallback_active = fallback_positions & ~primary_positions
cascade_returns = (
primary_equity * primary_positions
+ d * fallback_equity * fallback_active
)
equity_curve = np.cumprod(1 + cascade_returns)
peak = np.maximum.accumulate(equity_curve)
drawdown = (equity_curve - peak) / peak
max_dd = drawdown.min()
total_pnl = equity_curve[-1] - 1
sharpe = (
np.mean(cascade_returns) / np.std(cascade_returns)
* np.sqrt(525_600) # minutes per year
) if np.std(cascade_returns) > 0 else 0
active_minutes = np.sum(primary_positions | fallback_active)
active_days = active_minutes / (24 * 60)
pnl_per_day = total_pnl / active_days if active_days > 0 else 0
results.append(CascadeResult(
dual_size=d,
total_pnl=total_pnl,
max_dd=max_dd,
sharpe=sharpe,
pnl_per_active_day=pnl_per_day,
))
return sorted(results, key=lambda r: r.sharpe, reverse=True)
Крипто стратегиялары үчүн типтүү оптимум: dual_size 0.05-0.10 диапазонунда (толук позициянын 5-10%). Стратегия B негизги катары (MaxDD 0.75%) жана Стратегия A резерв катары (MaxDD 0.9%):
Просадка чектөөсү байланыштыруучу эмес — оптималдуу маани каскаддык Шарп коэффициенти менен аныкталат. Практикада тор издөө көбүнчө (6.8%) берет.
Балл негизиндеги бөлүштүрүү
Композиттик балл боюнча рейтингделген стратегиялар — ишеним көрсөткүчүн тууралоо кичине үлгүлөрдү жазалайт, фандинг чыгымдары таза артыкчылыкты азайтат
Экиден көп стратегия болгондо, каскад балл негизиндеги бөлүштүрүүгө чейин жалпыланат.
Активдүү убакытка карата PnL боюнча рейтингдөө
Активдүү убакытка карата PnL макаласында толук сүрөттөлгөндөй, стратегиянын баллы төмөнкүлөрдү эске алуу менен эсептелет:
- Активдүү күнгө PnL — капиталды пайдалануунун натыйжалуулугу
- Ишеним көрсөткүчүн тууралоо — кичине үлгүлөр үчүн жаза (t-бөлүштүрүү)
- Фандинг чыгымдары — левериждин чыныгы наркы (Фандинг чендери)
- MaxLev — просадканы эске алуу менен масштабдоо (Чыгым-пайда асимметриясы)
Сейрек стратегиялар үчүн ишеним көрсөткүчүн тууралоо
40 бүтүмү бар Стратегия B олуттуу жаза талап кылат. Биз ишеним интервалынын төмөнкү чегин колдонобуз:
import scipy.stats as st
import numpy as np
def confidence_factor(trade_returns: np.ndarray, confidence: float = 0.95) -> float:
"""Confidence factor: 0..1, penalty for small samples."""
n = len(trade_returns)
if n < 10:
return 0.0
mean_r = np.mean(trade_returns)
if mean_r <= 0:
return 0.0
se = np.std(trade_returns, ddof=1) / np.sqrt(n)
t_crit = st.t.ppf(1 - (1 - confidence) / 2, df=n - 1)
ci_lower = mean_r - t_crit * se
return max(0.0, ci_lower / mean_r)
cf_b = confidence_factor(np.random.normal(0.0067, 0.028, 40))
cf_a = confidence_factor(np.random.normal(0.0011, 0.008, 500))
Фандинг чыгымын бириктирүү
Түбөлүк фьючерстерде фандинг ар 8 саат сайын төлөнөт. левериджи жана орточо чен болгондо:
MaxLev = 55x жана орточо фандинг чени 0.01% болгон Стратегия A үчүн:
Активдүү күнгө PnL = 0.49% болгондо, таза PnL терс: /күн. Стратегия толук левериджде пайдасыз. Толук анализ Фандинг чендери сиздин левериджиңизди өлтүрөт макаласында.
Көп стратегиялуу оркестратор

Архитектура
Оркестратор соода жуптарында стратегияны башкарат. Мүмкүн болгон позициялардын жалпы саны: . Бирок капитал чектелген — бир учурда ашпаган позицияларга (слоттарга) гана уруксат берилет.
┌─────────────────────────────────────────────┐
│ ORCHESTRATOR │
│ │
│ Signal Queue (sorted by score): │
│ ┌──────────────────────────────────────┐ │
│ │ 1. Strategy C × ETHUSDT score=223 │ │
│ │ 2. Strategy B × BTCUSDT score=142 │ │
│ │ 3. Strategy A × SOLUSDT score=100 │ │
│ │ 4. Strategy C × BTCUSDT score=89 │ │
│ │ 5. Strategy A × ETHUSDT score=76 │ │
│ └──────────────────────────────────────┘ │
│ │
│ Active Slots (max_parallel = 3): │
│ ┌──────────────────────────────────────┐ │
│ │ Slot 1: Strategy C × ETHUSDT [FULL] │ │
│ │ Slot 2: Strategy B × BTCUSDT [FULL] │ │
│ │ Slot 3: Strategy A × SOLUSDT [DUAL] │ │
│ └──────────────────────────────────────┘ │
│ │
│ Conflict Rules: │
│ - One position per pair │
│ - Primary displaces fallback on same pair │
│ - Higher score wins for cross-pair slots │
└─────────────────────────────────────────────┘
Слоттарды башкаруу
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
import heapq
import time
class SlotType(Enum):
FULL = "full" # primary strategy, 100% position
DUAL = "dual" # fallback strategy, dual_size position
@dataclass
class Signal:
strategy_id: str
pair: str
direction: str # "long" | "short"
score: float
is_primary: bool # primary or fallback
timestamp: float
@dataclass(order=True)
class Slot:
"""A single orchestrator slot."""
priority: float = field(compare=True) # negative score for min-heap
strategy_id: str = field(compare=False)
pair: str = field(compare=False)
slot_type: SlotType = field(compare=False)
entry_time: float = field(compare=False)
class Orchestrator:
"""
Multi-strategy orchestrator with cascade mode.
Manages N strategies x M pairs within max_parallel_positions slots.
Primary strategies have unconditional priority over fallback.
"""
def __init__(
self,
max_parallel_positions: int = 10,
dual_size: float = 0.068,
min_score: float = 0,
):
self.max_parallel = max_parallel_positions
self.dual_size = dual_size
self.min_score = min_score
self.active_slots: dict[str, Slot] = {} # pair -> Slot
self.pending_signals: list[Signal] = []
def on_signal(self, signal: Signal) -> Optional[dict]:
"""
Process a new signal. Returns an action or None.
Actions:
- {"action": "open", "pair": ..., "size": ..., "slot_type": ...}
- {"action": "replace", "pair": ..., "close_strategy": ..., "open_strategy": ...}
- None (signal rejected)
"""
if signal.score < self.min_score:
return None
pair = signal.pair
if pair in self.active_slots:
existing = self.active_slots[pair]
if signal.is_primary and existing.slot_type == SlotType.DUAL:
self.active_slots[pair] = Slot(
priority=-signal.score,
strategy_id=signal.strategy_id,
pair=pair,
slot_type=SlotType.FULL,
entry_time=signal.timestamp,
)
return {
"action": "replace",
"pair": pair,
"close_strategy": existing.strategy_id,
"open_strategy": signal.strategy_id,
"size": 1.0,
}
if signal.score > -existing.priority:
slot_type = SlotType.FULL if signal.is_primary else SlotType.DUAL
size = 1.0 if signal.is_primary else self.dual_size
self.active_slots[pair] = Slot(
priority=-signal.score,
strategy_id=signal.strategy_id,
pair=pair,
slot_type=slot_type,
entry_time=signal.timestamp,
)
return {
"action": "replace",
"pair": pair,
"close_strategy": existing.strategy_id,
"open_strategy": signal.strategy_id,
"size": size,
}
return None # existing has higher priority
if len(self.active_slots) < self.max_parallel:
slot_type = SlotType.FULL if signal.is_primary else SlotType.DUAL
size = 1.0 if signal.is_primary else self.dual_size
self.active_slots[pair] = Slot(
priority=-signal.score,
strategy_id=signal.strategy_id,
pair=pair,
slot_type=slot_type,
entry_time=signal.timestamp,
)
return {
"action": "open",
"pair": pair,
"strategy": signal.strategy_id,
"size": size,
"slot_type": slot_type,
}
worst_pair = min(
self.active_slots,
key=lambda p: -self.active_slots[p].priority,
)
worst_slot = self.active_slots[worst_pair]
if signal.score > -worst_slot.priority:
del self.active_slots[worst_pair]
slot_type = SlotType.FULL if signal.is_primary else SlotType.DUAL
size = 1.0 if signal.is_primary else self.dual_size
self.active_slots[pair] = Slot(
priority=-signal.score,
strategy_id=signal.strategy_id,
pair=pair,
slot_type=slot_type,
entry_time=signal.timestamp,
)
return {
"action": "replace",
"pair": pair,
"close_strategy": worst_slot.strategy_id,
"close_pair": worst_pair,
"open_strategy": signal.strategy_id,
"size": size,
}
return None # all active slots have higher scores
def on_exit(self, pair: str) -> None:
"""Strategy closed a position."""
if pair in self.active_slots:
del self.active_slots[pair]
def utilization(self) -> float:
"""Current slot utilization."""
return len(self.active_slots) / self.max_parallel
def fill_efficiency_snapshot(self) -> float:
"""Weighted utilization: FULL=1.0, DUAL=dual_size."""
total = sum(
1.0 if s.slot_type == SlotType.FULL else self.dual_size
for s in self.active_slots.values()
)
return total / self.max_parallel
Конфликттерди чечүү
Үч деңгээлдүү конфликт:
1-деңгээл — Бир жуп, бир багыт. Жогорку баллы бар стратегия жеңет. Эгер экөө тең негизги болсо — балл жеңүүчүнү аныктайт. Эгер бирөө негизги, экинчиси резерв болсо — негизги шексиз жеңет.
2-деңгээл — Бир жуп, карама-каршы багыт. Тыюу салынган: бир жупта бир учурда лонг да, шорт да боло албайсыз. Эң жогорку баллы бар стратегия жеңет.
3-деңгээл — Жуп аралык атаандаштык. Бардык слоттор бош болбогондо, жаңы сигнал эң төмөн баллы бар слотту ордунан кетирет. Бул приоритет кезеги катары иштейт.
Каскаддык бэктестилөө: Методология
Биргелешкен симуляция: кабатташуу зоналары бар негизги жана резервдик equity ийри сызыктары жана бириктирилген каскаддык натыйжа
Эмне үчүн жөн гана PnL кошууга болбойт
Жөнөкөй ыкма: ар бир стратегияны өзүнчө бэктестилөө, PnL кошуу. Бул үч себеп боюнча шишиктелген натыйжа берет:
-
Убакыттын кабатташуусу. Негизги жана резерв бир учурда активдүү болгондо, резерв соода кылбашы керек (же dual_size менен соода кылат). Жөнөкөй кошуу бул кабатташууну эске алган жок.
-
Капитал чектөөсү. Жалпы позиция чектелген. Эгер 5 стратегия бир учурда ачылгысы келсе, бирок болгону 3 слот болсо — эки стратегия кирбейт. Алардын PnL эсептелбейт.
-
Транзакция чыгымдары. Каскаддык которуу (резервди жабуу, негизгини ачуу) жеке бэктесттерде жок кошумча комиссияларды жаратат.
Биргелешкен симуляция
Туура каскаддык бэктест — бул бардык стратегиялардын жалпы убакыт тилкесиндеги биргелешкен симуляциясы:
import numpy as np
from typing import NamedTuple
class Trade(NamedTuple):
strategy: str
pair: str
entry_time: int # minute index
exit_time: int # minute index
pnl_per_minute: float # log-return per minute
is_primary: bool
score: float
def backtest_cascade(
all_trades: list[Trade],
total_minutes: int,
max_slots: int = 10,
dual_size: float = 0.068,
switch_cost: float = 0.0006, # 0.06% round-trip
) -> dict:
"""
Joint simulation of cascade portfolio.
Walk through each minute, apply orchestrator rules,
calculate PnL accounting for overlap and slot constraints.
"""
entries = {}
exits = {}
active_trades = {} # trade_id -> Trade
for i, trade in enumerate(all_trades):
entries.setdefault(trade.entry_time, []).append((i, trade))
exits.setdefault(trade.exit_time, []).append((i, trade))
active_slots = {} # pair -> (trade_id, SlotType)
equity = np.ones(total_minutes)
switch_costs_total = 0.0
for t in range(1, total_minutes):
for trade_id, trade in exits.get(t, []):
if trade.pair in active_slots:
slot_id, _ = active_slots[trade.pair]
if slot_id == trade_id:
del active_slots[trade.pair]
new_signals = sorted(
entries.get(t, []),
key=lambda x: x[1].score,
reverse=True,
)
for trade_id, trade in new_signals:
pair = trade.pair
if pair in active_slots:
existing_id, existing_type = active_slots[pair]
existing_trade = all_trades[existing_id]
if trade.is_primary and existing_type == SlotType.DUAL:
active_slots[pair] = (trade_id, SlotType.FULL)
switch_costs_total += switch_cost
continue
if trade.score > existing_trade.score:
slot_type = SlotType.FULL if trade.is_primary else SlotType.DUAL
active_slots[pair] = (trade_id, slot_type)
switch_costs_total += switch_cost
elif len(active_slots) < max_slots:
slot_type = SlotType.FULL if trade.is_primary else SlotType.DUAL
active_slots[pair] = (trade_id, slot_type)
minute_return = 0.0
for pair, (trade_id, slot_type) in active_slots.items():
trade = all_trades[trade_id]
size = 1.0 if slot_type == SlotType.FULL else dual_size
minute_return += trade.pnl_per_minute * size
equity[t] = equity[t - 1] * (1 + minute_return)
peak = np.maximum.accumulate(equity)
max_dd = ((equity - peak) / peak).min()
total_pnl = equity[-1] - 1 - switch_costs_total
return {
"total_pnl": total_pnl,
"max_dd": max_dd,
"switch_costs": switch_costs_total,
"equity_curve": equity,
}
Которуудагы транзакция чыгымы
Ар бир каскаддык которуу (резервден -> негизгиге) талап кылат:
- Резерв позициясын жабуу: taker комиссиясы (Binance фьючерстеринде 0.04%)
- Негизги позицияны ачуу: taker комиссиясы (0.04%)
- Спред: ~0.01-0.02%
Жалпы которуу чыгымы: которуу үчүн ~0.06-0.10%. Мезгил ичинде 100 которуу болгондо:
Бул олуттуу сумма. Кыйла жиш которулган каскад транзакция чыгымдарынан улам жалгыз стратегиядан төмөн натыйжа көрсөтүшү мүмкүн.
Көп жуптуу кеңейтүү: M жупта N стратегия
N стратегияны M соода жубу менен байланыштырган тармак — корреляция күчү натыйжалуу диверсификацияны аныктайт
Комбинация мейкиндиги
10 жупта 3 стратегия = 30 мүмкүн болгон сигнал. max_slots = 5 болгондо, оркестратор балл боюнча эң жогорку 5-ти тандайт. Бул комбинаторикалык маселе: ар бир учурда мүмкүн болгон портфель.
Практикада гриди алгоритм (балл боюнча иреттөө, жогорудан төмөн карай толтуруу) убактысында оптималдууга жакын натыйжаларды берет.
Жуптар арасындагы корреляция
Крипто жуптары катуу корреляцияланган. BTC түшөт — ETH, SOL, AVAX бирге түшөт. Бул 5 башка жупта 5 лонг позиция иш жүзүндө "крипто рыногундагы" бир чоң позиция дегенди билдирет.
Сигналдар корреляциясы макаласында толук анализделгендей, көз каранды эмес позициялардын натыйжалуу саны:
мында — жуптар арасындагы орточо корреляция.
жана болгондо:
Корреляцияланган жуптардагы беш позиция 1.3 көз каранды эмес позицияга тете. Диверсификация иш жүзүндө жок.
Каскад үчүн практикалык натыйжалар
def effective_diversification(
positions: list[dict], # [{"pair": "BTCUSDT", "direction": "long"}, ...]
correlation_matrix: np.ndarray,
pair_index: dict[str, int],
) -> float:
"""
Calculate effective diversification of open positions.
Returns:
N_eff / N — diversification coefficient (0..1)
"""
n = len(positions)
if n <= 1:
return 1.0
total_corr = 0.0
pairs_count = 0
for i in range(n):
for j in range(i + 1, n):
idx_i = pair_index[positions[i]["pair"]]
idx_j = pair_index[positions[j]["pair"]]
rho = correlation_matrix[idx_i, idx_j]
if positions[i]["direction"] != positions[j]["direction"]:
rho = -rho
total_corr += rho
pairs_count += 1
avg_rho = total_corr / pairs_count if pairs_count > 0 else 0
n_eff = n / (1 + (n - 1) * max(0, avg_rho))
return n_eff / n
Оркестратор слоттарды толтурганда корреляцияны эске алышы керек. Эки вариант бар:
- Диверсификация бонусу: иреттөө учурунда корреляцияланбаган жуптардагы стратегиялардын баллына бонус кошуу.
- Корреляция чеги: корреляцияланган жуптардагы бир багыттагы позициялардын санын чектөө.
Каскаддык оптималдаштыруу конвейери
Маалыматтарды даярдоодон баштап ырастоо жана тирүү оркестрацияга чейинки сегиз байланышкан этап — ар бири мурункусуна негизделет
Маалыматтардан өндүрүшкө чейинки толук конвейер 8 этаптан турат:
0-этап: Маалыматтарды даярдоо
Тарыхый маалыматтарды жүктөө, көп убакыт тилкелүү жетүү үчүн Parquet кэшин куруу. Натыйжалуу кэштөөсүз кийинки этаптар жол берилгис жай болот.
1-этап: TF + Узундук (Тоо чокусуна чыгуу тору)
Базалык убакыт тилкесин жана индикатор терезелеринин узундугун тандоо. Дөкүрөк тор: TF {1m, 5m, 15m, 1h, 4h} топтомунан, Length {10, 20, 50, 100, 200} топтомунан. Эң жакшы тор чекитинен баштап тоо чокусуна чыгуу.
2-этап: Бөлүнүү (Координаттык түшүү, 12 параметр)
Бөлүнүү параметрлерин (кирүүлөр/чыгуулар) оптималдаштыруу. 12 параметр боюнча координаттык түшүү — индикатор чектери, чыпкалар, стоп-лосстор, тейк-профиттер. Жогорку өлчөмдүү детерминисттик максат функциялары үчүн координаттык түшүү Optuna-дан арзаныраак.
3-этап: Мета-параметрлер (Координаттык түшүү)
Мета-параметрлер: максималдуу кармоо убактысы, чыгуу үчүн минималдуу PnL, трейлинг-стоп конфигурациясы. Дагы координаттык түшүү. Плато анализи аркылуу туруктуулукту текшерүү — эгер оптимум чекиттүү болсо, стратегия ашыкча оптималдаштырылган.
4-этап: Комбо оптималдаштыруу
Жуптар (Негизги, Резерв) боюнча тор издөө. Ар бир комбинация үчүн: dual_size тандоо, биргелешкен симуляция аркылуу каскаддык PnL эсептөө.
5-этап: Ырастоо
Көп деңгээлдүү ырастоо:
- Көп символдуу: стратегия оптималдаштыруу жубунда гана эмес, 10+ жупта текшерилет
- Walk-forward: жылыштыруучу IS/OOS терезеси
- Параметр туруктуулугу: ар бир этапта плато анализи
- Монте-Карло бутстрап: каскаддык PnL үчүн ишеним интервалдары
- Бэктест-тирүү паритети: бэктестти paper trading менен салыштыруу
6-этап: Рейтингдөө жана тандоо
Каскаддык комбинацияларды балл боюнча рейтингдөө. Топ-K комбинациялар 7-этапка өтөт. Балл ишеним көрсөткүчүн тууралоону, фандинг чыгымдарын жана fill_efficiency-ди эске алат.
7-этап: Оркестрация
Акыркы этап: оркестраторду каскаддык режимде стратегия жана жупта иштетүү. Слоттарды башкаруу, приоритет кезеги, конфликттерди чечүү — жогоруда сүрөттөлгөндүн бардыгы.
Натыйжалуулук анализи: Каскад менен жеке стратегиялар
Катар салыштыруу: каскаддык портфель бош убакытты пайдалануу аркылуу жеке стратегиялардан ашып түшөт
Теориялык каскад артыкчылыгы
Негизги убакыттын -ында PnL/күн = 0.49% менен соода кылат деп эсептейли. Резерв убакытта PnL/күн = 0.89% менен соода кылат. Кабатташуу = (көз карандысыздыкты болжолдоо менен).
Жалгыз негизги (Стратегия A):
Каскад (A негизги + C резерв):
Каскад пайдасы: резервден PnL-ге +31%, ал эми просадка минималдуу өсөт ( MaxDD-ге кошулат).
Каскад жардам бербеген учурлар
Каскад төмөнкү учурларда натыйжасыз:
- Негизги убакыттын >80%-ында активдүү. Бош убакыт аз — резерв үчүн орун жок.
- Стратегиялар катуу корреляцияланган. Негизги жана резерв бир учурда сигнал берет — кабатташуу жогору, ал эми резерв так негизги бош турганда бош турат.
- Которуу чыгымдары резерв PnL-ден ашып түшөт. Кыйла жиш которуу учурунда каскад комиссиялары резерв пайдасын жеп коет.
- dual_size өтө кичине. болгондо, резерв өз потенциалынын 1%-ын гана табат — комиссиялардан төмөн.
Салыштыруу таблицасы
| Конфигурация | Жылдык PnL | MaxDD | Sharpe | Которуу чыгымдары |
|---|---|---|---|---|
| Жалгыз Стратегия A | 26.8% | 0.9% | 1.42 | 0 |
| Жалгыз Стратегия C | 146.1% | 17% | 1.15 | 0 |
| Каскад A+C (d=0.068) | 35.2% | 2.06% | 1.58 | ~1.2% |
| Каскад B+A (d=0.068) | 19.4% | 1.36% | 1.71 | ~0.3% |
| 3 стратегиялуу оркестратор | 48.7% | 3.1% | 1.63 | ~2.1% |
Каскад A+C: негизги A резерв C-дан +8.4% алат. Sharpe бош убакытты пайдалануу аркылуу өсөт. MaxDD орточо өсөт ().
Убактылуу диверсификациянын математикасы
Жогорудагы каскад артыкчылыгы — бош убакытты толтуруу — стратегиялар китебин диверсификациялоонун эки түп-тамырынан ар башка жолунун бирөө, жана алар ар башкача масштабдалат. Айырманы туура түшүнүү каскаддын так эмнени сатып ала аларын жана сатып ала албасын көрсөтөт.
Базалык стратегия активдүү мезгил боюнча орточо мааниси жана волатилдиги бар i.i.d. кирешелерди тапты дейли, ошондуктан анын мезгилдик Шарп коэффициенти . Төмөндөгү ар бир Шарп коэффициенти менен жылдандырылган; иштелип чыккан мисалда мезгилине колдонулат (жылдандырылганы ), ал эми ар бир сан жабык формула менен эки ондук белгиге чейин дал келген 2,000,000-мезгилдик симуляциядан алынган.
Убактылуу диверсификация: Бош убакытты толтуруу
Убакыттын болгону бөлүгүндө рынокто болгон — калганында тегиз (нөлдүк киреше, бирок нөлдүк тобокелдик да) — стратегиянын толук убакыт тилкесиндеги Шарп коэффициенти
Бош убакыт орточо маанини -ге суюлтат, бирок стандарттык четтөөнү болгону -ге суюлтат, ошондуктан катыш катары төмөндөйт: болгондо жылдандырылган Шарп -дан -га чейин түшөт. Ошондуктан убакыттын -ында соода кылган жогорку ишенимдүү негизги стратегия толук equity ийри сызыгында орточо болуп көрүнөт.
Каскад бул бош убакытты толтурат. убакыт боюнча кесилишпеген стратегияларды алар чогуу бүтүндөй убакыт тилкесин жаба тургандай орнотуңуз — ар бир мезгилде так бирөө активдүү — жана бириктирилген агым кайрадан болот:
жабуу менен бир стратегиядан толук жабуу менен стратегияга өтүү Шарпты эсе жогорулатат — ырасталган: , , — бирок ал -те каныгат, б.а. жалгыз стратегиянын мезгилдик Шарп коэффициентинде. Убактылуу диверсификация китептин тобокелдикке туураланган кирешесин бир стратегия соода кылып жатканда тапкандан жогору көтөрө албайт, себеби ар бир мезгилде сиз так бир стратегияны кармайсыз: орточолоо жок, дисперсияны азайтуу жок. Ал сатып ала турганы — капиталды кайра пайдалануу: бир бирдик капитал бардык стратегияны ирети менен иштетет. Аларды бир мезгилде иштетүү үчүн сизге бирдик (же эсе левериж) керек болмок; каскад бардык артыкчылыкты бир бирдикте чогултат. Бул — тобокелдик жеңиши эмес, капитал натыйжалуулугунун жеңиши.
Корреляциялык диверсификация: Каскад баш тарткан √N
Экинчи түрү стратегияны бир мезгилде иштетет, капиталды бөлүштүрөт жана аларды ар бир мезгилде орточолойт. Жуп боюнча корреляциясы бар тең корреляцияланган стратегиялар үчүн,
бул корреляцияланбаган учурда () болот жана болгон сайын -ке карай кысылат. Ырасталган: 8 корреляцияланбаган стратегия жылдандырылган -ке жетет (б.а. ), бирок болгондо ошол сегиз болгону -ке жетет — жалгыз стратегиядан бир аз гана жакшы. Бул так көп жуптуу бөлүмдөгү натыйжалуу диверсификация дисконту: корреляция — -га салынган салык.
Kelly бөлүштүрүүсү — корреляциялык оптимум. Орточо маанилер вектору жана ковариация болгондо, өсүшкө оптималдуу салмактар , ал эми алар жеткен Шарп
бул масштабдоону так кайталайт (симуляция жана жабык формула дал келет: 8 корреляцияланбаган үчүн , болгондо ). — "ар бир мезгилде орточолоо" жазылганда кандай көрүнөрү.
Каскад иш жүзүндө эмнени сатып алат жана анын чеги
| Өлчөм | Убактылуу (каскад) | Корреляциялык (параллель) |
|---|---|---|
| Стратегиялар качан иштейт | убакыт боюнча кесилишпейт | бир мезгилде |
| Капитал | кайра пайдаланылат (1 бирдик баарын иштетет) | бөлүштүрүлөт / леверижделенет ( бирдик) |
| Шарп масштабдоосу | -те каныгат (бош орунду толтурат, толук жабууга ) | |
| Тобокелдикти азайтуу | жок (ар бир мезгилде бир стратегия) | , корреляция менен чектелген |
| Эмнени сатып алат | капитал натыйжалуулугу, рыногдо болуу убактысы | тобокелдикке туураланган киреше |
Бул экөө көбөйтүлөт. Чыныгы оркестратор ар бир мезгилде (алсыз корреляцияланган) стратегияны иштетет — мезгилдик -ды сатып алат — жана бул терезелерди убакыт боюнча жайгаштырат, капиталды кайра пайдаланат. Жалпы Шарп мезгилдик түзүлүш менен аныкталат,
болгондо ырасталган (жылдандырылган , , ), ал эми убактылуу жайгаштыруу капитал натыйжалуулугун көбөйтөт, Шарпты эмес.
Чек кайда. Таза каскад — бир мезгилде бир стратегия активдүү — жалпы Шарпы так -ке тете, кезекте канча стратегия күтүп тургандыгына карабастан. Ал рыногдо болуу убактысын жана капитал натыйжалуулугун максималдаштырат, бирок анын тобокелдикке туураланган кирешеси бир стратегиянын кирешеси менен чектелген. -тен ашуу үчүн мезгил ичинде диверсификациялоо керек — бир нече алсыз корреляцияланган стратегияны бир мезгилде иштетүү — жана бул пайда менен чектелет жана корреляция менен жоюлат. Дизайн эрежеси мындан келип чыгат: бош убакытты бир бирдик капиталда арзан кайтаруу үчүн каскадды колдонуңуз, ал эми сейрек кездешкен, кымбат бир мезгилдеги диверсификацияны чын эле корреляцияланбаган стратегияларга гана коротуңуз. Корреляцияланган стратегияларды чогултуу — убакыт боюнча же параллель түрдө — иш жүзүндө эч нерсе бербейт.
Оркестрация: Иш жүзүндөгү fill_efficiency
~78% толтуруу натыйжалуулугу: жылуулук картасы стратегиялар жана жуптар боюнча убакытты пайдаланууну көрсөтөт, жарык клеткалар активдүү соодасын билдирет
fill_efficiency параметри оркестратордун бош убакыттын кайсы бөлүгүн чын эле пайдаланарын аныктайт. Активдүү убакытка карата PnL макаласында көрсөтүлгөндөй, аны үч жол менен баалоого болот:
- Туруктуу константа (0.80) — дөкүрөк, бирок универсалдуу
- Аналитикалык баа аркылуу — корреляцияны эске алат
- Маалыматтардан симуляция — эң так
10 жупта 3 стратегиясы бар каскад үчүн:
def cascade_fill_efficiency(
strategies: list[dict], # [{"trading_time": 0.15, "is_primary": True}, ...]
n_pairs: int = 10,
correlation_factor: float = 3.0,
) -> float:
"""Estimate fill_efficiency for a cascade portfolio."""
n_eff = n_pairs / correlation_factor
primary_times = [s["trading_time"] for s in strategies if s["is_primary"]]
p_primary = 1 - np.prod([(1 - t) ** n_eff for t in primary_times])
fallback_times = [s["trading_time"] for s in strategies if not s["is_primary"]]
p_fallback = 1 - np.prod([(1 - t) ** n_eff for t in fallback_times])
fill = p_primary + (1 - p_primary) * p_fallback
return min(fill, 1.0)
strategies = [
{"trading_time": 0.05, "is_primary": True}, # Strategy B
{"trading_time": 0.15, "is_primary": True}, # Strategy A
{"trading_time": 0.45, "is_primary": False}, # Strategy C as fallback
]
eff = cascade_fill_efficiency(strategies, n_pairs=10, correlation_factor=3.0)
Практикалык сунуштар
Каскадды жайгаштыруу үчүн алты негизги сунуш — кичине баштоодон адаптивдүү кайра калибрлөөгө чейин
1. Эки стратегиядан баштаңыз
20 жупта дароо 10 стратегияны иштетпеңиз. 3-5 жупта бир негизги + бир резервден баштаңыз. Биргелешкен симуляциянын чыныгы жүрүм-турумга дал келерине көз жеткириңиз. Бэктест-тирүү паритети абдан маанилүү: эгер каскаддык бэктест тирүү соодадан 5-10%-га ажыраса — оркестратор логикасында ката бар.
2. dual_size тор издөөдөн, интуициядан эмес
Оптималдуу dual_size стратегиялардын так жубуна көз каранды. 6.8% — багыт, универсалдуу константа эмес. 1%-дан 30%-га чейин 0.5% кадам менен тор издөөнү жүргүзүп, Шарп максимумун тандаңыз.
3. Слот чеги архитектураны аныктайт
max_slots = 1 болгондо каскад жөнөкөй стратегия алмаштырууга айланат. max_slots = 50 болгондо чектөө байланыштыруучу эмес, жана маселе көз каранды эмес портфелге чейин азаят. Кызыктуу зона: max_slots = 3-10, мында слоттарды башкаруу натыйжаларга чын эле таасир этет.
4. Кечигүүнү эске алыңыз
Тирүү соодада каскаддык которуу шак эле болбойт. Резерв позициясын жабуу + негизгини ачуу = 2 API чакыруусу + тармак кечигүүсү + биржа дал келтирүүсү. Волатилдүү рынокто баа 200-500мс ичинде кыймылдашы мүмкүн. Слиппедж бюджетин пландаштырыңыз.
5. fill_efficiency-ди көзөмөлдөңүз
Өндүрүштөгү чыныгы fill_efficiency-ди көзөмөлдөңүз. Эгер ал бэктестелгенден олуттуу төмөн болсо — оркестратор күтүлгөндөй бош убакытты пайдаланбайт. Себептери: API кечигүүлөрү, кабыл алынбаган тапшырыктар, маржа чектөөлөрү.
6. Адаптивдүү оптималдаштырууну колдонуңуз
Каскад параметрлери (dual_size, балл салмактары, слот чектери) статикалык болбошу керек. Жаңы маалыматтар боюнча мезгилдүү кайра калибрлөө үчүн адаптивдүү терең түшүү колдонуңуз. Рынок өзгөрөт — каскад параметрлери да ошого жараша өзгөрүшү керек.
«Иллюзиясыз бэктесттер» сериясы: Корутунду
Толук система архитектурасы: математикадан ырастоого чейин жана тирүү оркестрацияга чейинки 13 өз ара байланышкан модуль
Бул макала 13+ макаладан турган сериянын финалы. Ар бир макала бэктесттен өндүрүшкө чейинки жолдогу бир так маселени чечти. Алардын кантип байланышары мындай:
Негиз: Киреше математикасы
Чыгым-пайда асимметриясы — кирешелердин мультипликативдик табияты, волатилдик суюлтуусу, Kelly критерийи. Бул — андан аркынын бардыгы үчүн математикалык негиз: эмне үчүн MaxDD левериждди аныктайт, эмне үчүн Sharpe чийки PnL-ден маанилүүрөөк, эмне үчүн симметриялуу R:R менен 50% жеңүү ылдамдыгы пайдасыз.
Ырастоо: Ишеним интервалдары жана бекемдик
Монте-Карло бутстрап — жалгыз чекиттик бааны ишеним интервалдары бар бөлүштүрүүгө айландыруу. Каалагандай көрсөткүч (PnL, MaxDD, Sharpe) болгону ишеним интервалы менен маанилүү.
Walk-Forward оптималдаштыруу — үлгүдөн тышкаркы ырастоо. Тарыхый маалыматтардагы бэктест — IS натыйжасы; WFO стратегиянын жаңы маалыматтарда кандай иштээрин көрсөтөт.
Плато анализи — параметр бекемдигин текшерүү. Эгер оптимум чекиттүү болсо, стратегия ашыкча оптималдаштырылган.
Бэктест-тирүү паритети — бэктестти чыныгы натыйжалар менен салыштыруу. Масштабдоо алдындагы акыркы текшерүү.
Чыныгы чыгымдар: Фандинг жана левериж
Фандинг чендери левериждиңизди өлтүрөт — түбөлүк фьючерстердеги левериждин жашыруун наркы. Фандингди эске албай, кооз бэктест чыгымга айланат.
Фандинг ченинин арбитражы — фандингди биржалар аралык стратегиялар аркылуу чыгымдан киреше булагына кантип айландырса болот.
Көрсөткүчтөр жана рейтингдөө
Активдүү убакытка карата PnL — портфелдеги стратегияларды рейтингдөө үчүн көрсөткүч. Чийки PnL масштабдалбайт; PnL/активдүү күн масштабдалат.
Сигналдар корреляциясы — корреляцияланган жуптар портфелиндеги натыйжалуу диверсификация.
Инфраструктура жана оптималдаштыруу
Көп убакыт тилкелүү бэктесттер үчүн Parquet кэши — тез итерациялар үчүн маалымат инфраструктурасы.
Адаптивдүү терең түшүү — адаптивдүү оптималдаштыруу: дөкүрөк тор -> перспективалуу зоналарда тактоо.
Optuna жана координаттык түшүү — оптимизатор тандоо: ызы-чуулуу максат функциялары бар төмөн өлчөмдөргө Optuna, тегиз максат функциялары бар жогорку өлчөмдөргө координаттык түшүү.
Polars жана Pandas — бэктестилөө үчүн DataFrame операцияларынын натыйжалуулугу.
Оркестрация (Ушул макала)
Каскаддык стратегиялар — мурунку бардык компоненттерди иштеген системага бириктирүү. Балл негизиндеги бөлүштүрүү активдүү убакытка PnL-ди, ишеним көрсөткүчүн тууралоону, фандинг чыгымдарын колдонот. Каскаддык режим бош убакытты толтурат. Биргелешкен симуляция портфелди ырастайт. Монте-Карло бутстрап каскаддык PnL үчүн ишеним интервалдарын берет.
Ар бир макала — көз каранды эмес модуль. Чогуу алар маалыматтарды жүктөөдөн стратегиялар портфелинин тирүү оркестрациясына чейинки толук конвейерди түзөт.
Корутунду
Каскад — стратегиялар портфелине жалгыз ыкма эмес. Бирок ал эң жөнөкөй жана практикалык ыкмалардын бирөө: негизги стратегия толук кубатта соода кылат, резерв бош убакытты азайтылган позиция менен толтурат. Эки негизги параметр (dual_size жана max_slots) көптөгөн конфигурациялар үчүн жетиштүү ийкемдүүлүк берет.
Үч маанилүү корутунду:
-
Каскад болгону биргелешкен симуляция аркылуу гана бэктестелиши керек. Жеке PnL-ди кошуу натыйжаларды шишиктет. Которуу чыгымдары, кабатташуу, слот чектөөлөрү — мунун бардыгы болгону биргелешкен симуляцияда камтылат.
-
dual_size PnL менен просадка ортосундагы тең салмактуулукту аныктайт. Типтүү оптимум — 5-10%. Sharpe боюнча тор издөө — ишенимдүү тандоо ыкмасы.
-
Оркестратор — балл негизиндеги приоритет кезеги. Баары ар бир сигнал үчүн бир санга (баллга) азаят. Score = f(PnL/активдүү күн, MaxLev, ишеним, фандинг). Эң жогорку баллы бар стратегиялар слот алат. Калгандары күтөт.
«Иллюзиясыз бэктесттер» сериясы бир нерсени көрсөтөт: кооз бэктест менен чыныгы пайданын ортосунда ондогон тузак жатат. Ар бир макала бирин жоёт. Каскаддык оркестрация — акыркы кадам: ырасталган стратегиялар жыйындысын иштеген портфелге айландыруу.
Пайдалуу шилтемелер
- López de Prado — Advances in Financial Machine Learning: Portfolio Construction
- Pardo, R. — The Evaluation and Optimization of Trading Strategies
- Ernest Chan — Algorithmic Trading: Winning Strategies and Their Rationale
- Perry Kaufman — Trading Systems and Methods, Chapter on Portfolio Allocation
- Tomasini, Jaekle — Trading Systems: A New Approach to System Development and Portfolio Optimisation
- Bailey, D.H. & López de Prado — The Deflated Sharpe Ratio
- Markowitz, H. — Portfolio Selection (1952)
- Kelly, J.L. — A New Interpretation of Information Rate (1956)
Дайынжай
@article{soloviov2026cascadestrategies,
author = {Soloviov, Eugen},
title = {Cascade Strategies: Priority Execution with Fallback Filling},
year = {2026},
url = {https://marketmaker.cc/ru/blog/post/cascade-strategies-orchestration},
version = {0.1.0},
description = {Finale of the "Backtests Without Illusions" series. How to build an orchestrator from N strategies x M pairs, implement cascade mode with priority and fallback filling, choose dual\_size, and why strategy portfolios cannot be backtested by summing PnL.}
}
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.