Оптимистичный grid (rr_grid_500k.json) показывал Sharpe 8-14 для $1-2.50. Honest данные с реальными exits (pump_short_moo_by_price): baseline Sharpe −2.15, потеря −212%/yr.
Разница из-за: (1) реальное моделирование стопов, (2) honest exits через bid в реальном времени, (3) включает halt-эффекты, (4) использует pm_close_vs_pc как proxy для open (более консервативно).
НО: с правильными фильтрами стратегия становится прибыльной. Найдено 2 рабочих стека.
Что делаем: Шортим утренние пампы дешёвых стоков ($1-$2.50) которые УЖЕ начали разваливаться к открытию. Заходим через MOO в 09:30 ET, держим до 09:35-09:55 ET, выходим.
Какие пампы берём (3 правила обязательны):
Какие пампы НЕ берём (фильтры):
Дополнительный сигнал-усилитель (опционально для S1):
Параметры исполнения:
Ожидаемая прибыль (HONEST):
Зелёные — где работает SHORT MOO→11:00. Красные — теряют деньги. Только $1-2.50 даёт edge; зона $2.50-5 убыточна на любом gap'е.
Чем дольше держим, тем хуже. Эта эквити деградирует к 11:00. Пампы НЕ затухают — они ПРОДОЛЖАЮТСЯ к 11:00 ET (squeeze дальше).
На правильно отобранных событиях держать до 09:55 OK (Sh 13). Дальше тоже окей. Но 09:35 безопаснее — раньше exit меньше вариативность.
Если в премаркете 09:00→09:25 цена ПАДАЕТ — отлично (fading_pre). Если РАСТЁТ — катастрофа (rallying_pre).
| Группа | n | Sharpe | WR | $/yr% |
|---|---|---|---|---|
| no_halt | 274 | −1.88 | 63% | −150% |
| had_halt | 44 | −3.29 | 64% | −68% |
Вывод: halt-events хуже даже несмотря на одинаковый WR. Слишком волатильно — большие losers съедают winners. SKIP if has_halt=1
| Quartile | vol range (20d avg) | n | Sh | WR |
|---|---|---|---|---|
| Q1 low | 0 — 1.6M | 80 | −2.51 | 56% |
| Q2 mid-low | 1.6M — 2.7M | 79 | −0.43 | 67% |
| Q3 mid-high | 2.7M — 5.2M | 79 | −0.60 | 68% |
| Q4 high | >5.2M | 80 | −3.66 | 61% |
Surprise: Q4 high-volume = ХУДШИЙ. Это мега-pump события (e.g. squeeze candidates). Q2-Q3 mid-volume — спокойные затухания.
Соотношение к BP: Q1-Q3 = 1.5-5M shares avg = comfortable для $30K BP (поток в 1 минуту PM ≈ $50-200K, наш ордер <30%).
Soft filter: avg_vol_20d < 5M (skip Q4)
Использовали как proxy: vol_early_share = доля PM объёма который произошёл в 04:00-07:00. Высокая = памп был "ранний", "stale" к 09:30.
| Класс | vol_early доля | n | Sh | WR |
|---|---|---|---|---|
| fresh | 0-20% | 163 | −2.89 | 60% |
| mid_early | 20-40% | 69 | −1.46 | 65% |
| early_majority | 40-60% | 52 | −0.87 | 69% |
| stale | >60% | 21 | −4.23 | 57% |
Парадокс: "early_majority" (40-60% объёма в раннем PM) — лучшая группа. Но "stale" (≥60%) — худшая.
Интерпретация: "stale" пампы (всё в early PM, ничего после 07:00) часто = sustained bid, реальный catalyst → в RTH продолжает расти. Это НЕ затухающий памп.
Вывод: Идея "ранний памп лучше шортить" работает только для "early_majority", не для extreme stale. Это выборочный фильтр, не основной.
Для production: добавить как мягкий boost (×1.2 size если early_majority), не hard-filter.
| Фактор | Что делать | Эффект | Confidence |
|---|---|---|---|
| Цена <$1 | SKIP всегда | Locate <5%, broker block | High |
| Цена $1-$2.50 | PRIMARY zone | Single positive cell | High |
| Цена $2.50-$5 | SKIP | All cells negative | High |
| Цена $5-$10 | SKIP | Все strategies underperform | Med |
| Gap <20% | SKIP | Sh −5.01 на $1-2.5×10-20 | High |
| Gap 20-50% | REQUIRE fading_pre filter | Sh 0.52 base, Sh 5.05 with filter | High |
| Gap 50-100% | CORE TRADES (best) | Sh 13.64, WR 88% | High |
| Gap >100% | SKIP (для pre-open module) | n <30, halt risk | Med |
| has_halt = 1 | SKIP всегда | Sh −3.29 | High |
| direction_900_925 < 0 | Сильный сигнал ENTER | Sh +0.45 baseline → Sh 5+ stack | High |
| direction_900_925 > 0 | SKIP | Sh −5.07 | High |
| avg_vol_20d >5M | SOFT skip | Sh −3.66 в Q4 | Med |
| vol_early_share 40-60% | BOOST size | Lowest negative class | Low |
| vol_early_share >60% | SKIP | "sustained bid" pumps continue | Med |
| exit_935 / exit_955 | USE | Шире окно после = деградация | High |
| exit_1100 | AVOID на baseline | Хорошо ТОЛЬКО на правильно отобранных | High |
Что: Запустить paper-trading на 1 месяц с обоими стеками одновременно. Цель — подтвердить Sh ≥ 3 на live данных.
Universe фильтр:
def is_eligible(event):
# HARD SKIPs
if event.prev_close < 1.0: return False, "sub_1$"
if event.prev_close >= 2.5: return False, "above_2.5$"
if event.gap_pct < 20: return False, "gap_too_small"
if event.gap_pct >= 100: return False, "extreme_pump_skip"
if event.has_halt == 1: return False, "halt_yesterday"
if event.avg_vol_20d > 5_000_000: return False, "high_volume_squeeze_risk"
# STACK selection
if event.gap_pct >= 50:
return True, "S_gap50" # primary stack — gap 50-100
if event.direction_900_925 < 0:
return True, "S1_fading" # gap 20-50 + fading pre
return False, "gap_2050_no_fading"
Параметры:
| Param | Value | Reason |
|---|---|---|
| Entry | SHORT MOO 09:30 ET | Backtested base |
| Primary exit | 09:35 ET market | Sh max в обоих stacks |
| Backup exit | 09:55 ET если 09:35 missed | Sh ≈ same |
| Hard cutoff | 11:00 ET | Risk control |
| BP / trade | $20-30K | Liquidity safe |
| Risk / trade | $150 | Cap |
| Max concurrent | 2-3 | ~71 events/yr ≈ 1-2/week |
| SL / TP | 0.5% / 2% | From original grid (still valid for $1-2.5) |
Текущий dataset имеет 26 событий gap 100-200% в $1-10 (n меньше 30 порога). Эти extreme пампы исключены из текущей стратегии. Открываем отдельный pipeline:
Идея с прошлого обсуждения: вчера +50% pump, сегодня open флет/-10%. Не в текущем dataset напрямую (need prev_day_high enrichment).
events_day2_fade.parquet через merge с прошлым днём pump_events| Контроль | Покрывает |
|---|---|
| Locate-check pre-trade | Cancel SKIP if no locate available (prevent failed orders) |
| Halt-aware exit | Force close on resume after halt (don't wait for stop) |
| Spread blowout cancel | Cancel MOO if spread >1% at 09:29:55 |
| PM stop-loss orders | Place STOP-LIMIT в PM for late-entered shorts (Day-2 fade) |
| Real-time P&L circuit | Already in adaptive_risk_gates.py — wire to new module |
| Telegram /override | Manual kill switch via existing TG bot |
| Year | n | Mean exit_1100 | WR |
|---|---|---|---|
| 2024 (Apr-Dec) | 10 | +7.00% | 100% |
| 2025 (full) | 27 | −0.73% | 70% |
| 2026 (Jan-Apr) | 7 | +5.96% | 86% |
2025 — слабый год. Возможно regime shift. 2024 и 2026 сильны. Need watch — если 2026 H2 деградирует, переоценить.
Conservative: применяем 2025 weak year как baseline → ~$10-15K/yr
Balanced: 3y average → $25-30K/yr
Aggressive: 2026 trend → $35-40K/yr (вряд ли устойчиво)
Capital allocation:
# broker/strategies/moo_1100_sub10/scorer.py
from typing import Optional, Tuple
HARD_PRICE_FLOOR = 1.0
HARD_PRICE_CEIL = 2.5 # exclusive
GAP_MIN = 20.0
GAP_MAX = 100.0 # exclusive
GAP_STRONG = 50.0 # gap_pct >= 50 → automatic eligible
HIGH_VOL_FLOOR = 5_000_000
def score_sub10_pump(event) -> Tuple[bool, str, dict]:
"""Returns (eligible, stack_name, params)"""
# Hard skips
if event.prev_close < HARD_PRICE_FLOOR:
return False, "skip_below_floor", {}
if event.prev_close >= HARD_PRICE_CEIL:
return False, "skip_above_ceiling", {}
if event.gap_pct < GAP_MIN or event.gap_pct >= GAP_MAX:
return False, "skip_gap_oob", {}
if event.has_halt:
return False, "skip_halt", {}
if event.avg_vol_20d and event.avg_vol_20d > HIGH_VOL_FLOOR:
return False, "skip_high_vol", {}
# Stack selection
if event.gap_pct >= GAP_STRONG:
return True, "S_gap50", {
"tp_pct": 0.02, "sl_pct": 0.005,
"primary_exit": "09:35", "hard_cutoff": "11:00",
"bp": 30_000, "size_mult": 1.0,
}
if event.direction_900_925 is not None and event.direction_900_925 < 0:
return True, "S1_fading", {
"tp_pct": 0.02, "sl_pct": 0.005,
"primary_exit": "09:35", "hard_cutoff": "09:55",
"bp": 25_000, "size_mult": 0.8,
}
return False, "skip_no_signal", {}
| Файл | Что использовали |
|---|---|
pump_short_moo_by_price.parquet | 4234 SHORT MOO trades с реальными exits 09:35-11:00 — основной honest источник |
pump_pm_accumulation_long.parquet | 858 events с timing breakdown (vol_early/mid/late share) |
pump_halt_history.parquet | 4359 events with has_halt, n_luld_pause |
pump_pre_open_entries.parquet | 2575 events с p_900, p_925, direction_900_925 |
events_v2.parquet (asym v2) | 3200 events для общего grid (сравнить с honest) |
Output files:
research_results/engine_v1_rerun_apr27/sub10_full_results.jsonresearch_results/engine_v1_rerun_apr27/sub10_master.parquetresearch_results/engine_v1_rerun_apr27/sub10_grid.json