simulated trades on assets with paper: true · same entry + exit logic, sim'd fills with adverse slippage
⚠ Pre-2026-04-30 10:05 UTC trades are biased downward (vol_decay / no_move
exits were silently disabled). For viability decisions, trust only the post-cutoff window.
Cards covering pre-cutoff history are marked with ⚠.
Cumulative paper PnL—
Vertical line = post-fix cutoff (2026-04-30 10:05 UTC). Slope before is bug-suppressed; slope after is clean.
1-minute candlesticks · entry marker + price line · runs from 15min before entry to now
Recent activity
live tail of trader.log
most recent first
📍 Live strategy (2026-04-29)
Tick-level wick trigger (per-asset thresholds) gated by a
5m EMA20 trend filter and a CVD Z-score
(60s window, 2.0σ; paper assets only — xyz:CL track-only). Sizing is
% of total equity, captured per-asset. Multi-asset live = xyz:CL only;
23 paper assets running V2 in simulation. See the Strategy
tab for the per-instrument table and the full filter / exit stack.
The backtest below uses the historical 1m spike model
(close-open ≥ threshold + vol ≥ N×). Useful for calibrating thresholds across historical
news events; not a perfect replay of live wick behavior (wick uses intra-candle high/low,
spike uses close-only, and this backtest does NOT apply the 5m EMA / CVD filters that
run live). Use sim_wick_entry.py /
sim_v2_threshold_sweep.py on the
server for filter-faithful replays.
⟳ Fetching candles…
📰 News Events mode: shows only triggers that fired during known real news events
(Iran war, ceasefire, Trump posts, OPEC decisions). For each event, the first 1m candle
meeting the threshold within 30 minutes is used as the entry. Approximates the wick strategy's
behavior for calibration; not a tick-level replay.
⚠️ All Triggers mode: shows every candle that crossed the price+volume threshold.
Useful for calibrating thresholds but not representative of actual live trade frequency.
TRADES
0
WIN RATE
0%
AVG P&L
0%
TOTAL P&L
$0
EXIT REASONS
No triggers found. Try adjusting thresholds or start date.
LegendWick path — fresh entries (only)RT path — re-entry onlyExitBackground / support
Single fresh-entry path: wick.
RT gated to re-entry window since 2026-04-23.
Entry → position → exit → re-entry
%%{init:{'theme':'base','themeVariables':{
'fontFamily':'SF Mono, Fira Code, monospace',
'fontSize':'12px',
'primaryColor':'#0f1a2e','primaryTextColor':'#e2e8f0','primaryBorderColor':'#334155',
'lineColor':'#475569','secondaryColor':'#111827','tertiaryColor':'#1f2937',
'clusterBkg':'#0b1120','clusterBorder':'#1e293b',
'edgeLabelBackground':'#0b1120','titleColor':'#e2e8f0'
}}}%%
flowchart TD
subgraph SRC["Continuous inputs"]
direction LR
WS["AllMidsSubscription dex=xyz (every tick)"]
CS["CandleSubscription 1m (forming + closed candles)"]
BG["Background news TS RSS 30s · X fast 5s X regular 30s · phone webhook"]
end
%% Shared resources
BG --> CR["news_cache_refresher_loop every 20s if new posts Haiku LLM → sentiment"]
CR -. fills .-> NC[(news_cache TTL 90s + persistent last_confirmed_sentiment)]
CS -- forming updates --> PC["_pending_candle (open + OHLC so far)"]
WS --> TB["_tick_buffer last 600 ticks ≈10min"]
CS --> PS["pre_scrape_loop mid-candle ≥0.2% → warms news cache"]
PS -. fills .-> NC
%% ─── SOLE FRESH-ENTRY PATH: WICK ────────────────────────────────
WS --> CWT
PC --> CWT
CWT["`**WICK TRIGGER** (every tick, per-asset)
|tick − candle.open| / open ≥ asset.wick_pct
AND in-progress vol / 20c_avg ≥ asset.vol_ratio
dedup: once per candle`"]
CWT -- fires --> EMA{"`**5m EMA20 trend filter**
bullish wicks: 5m EMA20 sloping UP
bearish wicks: sloping DOWN
(E10, deployed 2026-04-28)`"}
EMA -- counter-trend --> SKIPF["filter: counter-trend wick → skip"]
EMA -- trend-aligned --> CVD{"`**CVD Z-score gate** (paper only; xyz:CL track-only)
60s window vs 5min history
bullish: Z ≥ +2.0σ; bearish: Z ≤ −2.0σ
bypass if <10 trades in window
(E11, deployed 2026-04-28)`"}
CVD -- order flow disagrees --> SKIPC["filter: CVD opposite → skip"]
CVD -- order flow agrees --> WSIG["PriceSignal type = 'wick' entry_price = tick price"]
WSIG --> CTL["`**confirmation_trade_loop**
type == 'wick'?
→ SKIP news check
→ open position`"]
CTL --> ENT
%% ─── RT PATH: RE-ENTRY ONLY (gated 2026-04-23) ──────────────────
TB --> RT["`**check_realtime_entry()** (polled 1s)
SWEEP: velocity ≥ 0.10% / 10s
AND dir-consistency ≥ 80%
CHAOTIC: 10s vol OR tick rate
≥ 1.5× / 2× of 5-min baseline`"]
RT -- "sweep or chaotic" --> GATE{"re-entry window active AND direction matches stored catalyst?"}
GATE -- "no" --> SKIP["logged as 'no re-entry window' or 'opposite-direction' → skip"]
GATE -- "yes" --> PFL["`**price_first_rt_loop**
skip news check
→ open position
(source = 'reentry')`"]
PFL --> ENT
ENT{{"**open_position()** asyncio.Lock · re-checks has_position size = total_equity × asset.size_pct%"}}
ENT --> POS["`**IN POSITION**
Hard SL/TP placed on-chain
V2 scale-out armed: 25%/25%/25%/25% @ +1/+2/+5/+10%
parabolic skip · BE-stop after first partial`"]
%% ─── PARTIAL SCALE-OUTS (V2, X8 deployed 2026-04-27) ───
POS --> SO{"`**check_partial()** every tick
current MFE crossed next level?
(slice ≥ HL $10 min-notional)`"}
SO -- "vol accelerating" --> SOSK["parabolic skip → recorded, ride the tail"]
SO -- "slice < $10" --> SOMN["min-notional skip (2026-04-29: account too small for 25% slice)"]
SO -- "fire" --> SOFIRE["reduce-only IoC BE-stop arms after 1st"]
SOFIRE -. residual --> POS
%% ─── EXITS ───
POS --> EX1{{"Exit checks every tick + every candle close"}}
EX1 -- "tick pnl ≤ −1.0% (or 0% post-partial)" --> X1["soft stop-loss"]
EX1 -- "price hits ∓1.5% / +10%" --> X2["hard SL/TP (on-chain)"]
EX1 -- "3 candles, peak PnL < 0.05%" --> X3["no-movement cut"]
EX1 -- "2c vol < 20% trigger AND close pnl > 0" --> X4["volume decay"]
X1 --> CLOSE["close_position() → market_close → cancel hard SL/TP"]
X2 --> CLOSE
X3 --> CLOSE
X4 --> REENT["`**re-entry window** 60 min
direction + sentiment stored
→ RT path now live`"]
REENT -. grants pass .-> GATE
CLOSE --> COOL["cooldown 600s → idle"]
%% Disabled paths (shown for context)
CS -. disabled .-> LG["spike trigger (spike_enabled=false)"]
LG -. disabled .-> SUS["sustained trigger (sustained.enabled=false)"]
classDef price fill:#2a1f00,stroke:#854d0e,color:#fde68a
classDef reent fill:#0f2a1b,stroke:#166534,color:#86efac
classDef share fill:#1f2937,stroke:#374151,color:#cbd5e1
classDef gate fill:#111827,stroke:#475569,color:#e2e8f0,stroke-width:2px
classDef exit fill:#2a0808,stroke:#7f1d1d,color:#fca5a5
classDef disabled fill:#1a1a2e,stroke:#3a3a4e,color:#6b6b82,stroke-dasharray:4 4
classDef skip fill:#1a1a2e,stroke:#64748b,color:#94a3b8,stroke-dasharray:4 4
class CWT,WSIG,CTL,EMA,CVD price
class RT,PFL,NC,BG,CR,PS,GATE,REENT reent
class WS,CS,TB,PC share
class EX1,X1,X2,X3,X4,CLOSE,COOL,SO,SOFIRE exit
class ENT,POS gate
class LG,SUS,SKIP,SKIPF,SKIPC,SOSK,SOMN disabled
Plain-English walkthrough
① WICK path — the sole fresh-entry path.
On every tick, per asset, the bot asks: has the current 1-minute candle's
intra-minute excursion from its own open reached the asset's
wick_pct threshold, AND is the in-progress volume ≥
vol_ratio × the 20-candle average? Per-asset thresholds
are tuned by sim_v2_threshold_sweep.py — see the
"Per-instrument" table below.
A wick fire then runs through two filters before becoming a trade:
5m EMA20 trend filter — bullish wicks need
the 5m EMA20 sloping UP, bearish DOWN. Backtest: paper +34%, oil flipped −$8.22 → +$2.65
on 677 trades. Suppresses counter-trend exhaustion fires.
CVD Z-score gate (paper assets only;
xyz:CL is track-only) — 60s aggressor-side flow normalized vs 5min history; require
Z ≥ +2.0σ for bullish, ≤ −2.0σ for bearish. Bypasses if <10 trades in window
(low-liquidity guard). Per Markwick 2022.
Both filters pass → confirmation_trade_loop sees
type='wick', skips the news check, opens position. Sizing is
total_equity × asset.size_pct/100.
② RT path — re-entry only
(gated 2026-04-23). Once per second, last 600 ticks inspected for
SWEEP (fast + directional) or
CHAOTIC (activity spike vs 5-min baseline). RT fires only
when (a) a re-entry window is open AND (b) direction matches the stored catalyst — else
skipped. RT-fresh entries were the cause of a 24h drift trade on 2026-04-22 and were
retired then.
Re-entry window is only opened by a
volume decay exit — meaning we took profit while the
catalyst was likely still alive. 60 min. Any other exit (SL / no-move / hard SL/TP)
closes the window immediately.
Exits — V2 stack runs simultaneously:
Scale-out: 25% reduce-only at +1%, +2%, +5%, +10% MFE. Parabolic
skip if current candle's vol > avg of prior 3 (let fat tails ride). Min-notional
skip if 25% slice < HL's $10 floor (avoids the rejection-retry loop hit 2026-04-29).
BE-stop after first partial: once any partial fires, soft SL moves
from −1% to entry — risk-free residual.
Soft SL at −1% (bot tick-level), hard SL at −1.5%
and hard TP at +10% (on-chain, work even if bot is offline).
Volume decay: 2-candle avg vol < 20% of trigger AND in profit
AND ≥3 candles since entry → close.
No-move: 3 candles, peak PnL < 0.05%.
Entry criteriawick (primary)
Wick trigger — tick-level entry. On every
AllMids update, the price monitor compares the current tick to the still-forming 1m
candle's open. If the excursion clears the per-asset threshold AND the in-progress
volume is elevated vs recent history, a signal fires before the minute closes.
The signal then runs through two filters (5m EMA + CVD) before opening the position.
wick thresholdper asset (wick_pct) — see table
vol gateper asset (vol_ratio) vs 20c avg
5m EMA20 filtertrend-aligned only (E10) — paper +34%, oil +$10.87
CVD low-liquidity bypass< 10 trades in window → pass (no false-confidence)
news checknone — speed IS the signal
dedupone fire per 1m candle
entry pricethe tick that crossed threshold
sizingtotal_equity × size_pct% per asset
Backtests on file:sim_wick_entry.py (24 war-era events): 0.5% + 2× = +$6.52, 64% WR.
sim_5m_trend_filter*.py (E10): paper Δ +34%, oil flipped to +$2.65.
sim_cvd_formulation_sweep.py (E11): Z-score (60s/2σ) beats %-based and no-filter.
Per-asset thresholds from sim_v2_threshold_sweep.py.
Disabled triggers (spike
and sustained) are gated by config flags and no longer
produce entries — their exhaustion-chase profile didn't pay off (sweep 2026-04-20).
Exit criteriain position
position_monitor_loop runs four exit families in parallel:
scale-out partials, soft/hard SL, hard TP, and time-based (no-move, vol_decay). Hard
SL/TP sit on-chain so they fire even if the bot is down.
BE-stop armsoft SL → 0% once any partial fills (X9)
Stops & targets
Soft stop-lossentry × (1 ∓ 1.0%) · BE after first partial
Hard SL (on-chain safety net)entry × (1 ∓ 1.5%)
Hard TP (on-chain + wick-catcher)entry × (1 ± 10.0%)
Time / volume
No-movement cut3 candles, peak PnL < 0.05%
Volume-decay exit2c avg vol < 20% of trigger vol AND pnl > 0 AND ≥3c since entry
Timeoutforce-exit at 120 candles (~2h on 1m) — restored 2026-04-30
Hard TP at 10% is a dual-purpose ceiling: safety net if the bot is offline, AND a
wick-catcher that locks profits on intra-candle spikes that vol_decay's close-based
check would otherwise miss (validated: 2026-03-09 Hormuz short hit +10% intra-low that
would've given back to +6.1% on close-peak exits).
On any final exit (not partial), hard SL/TP orders are cancelled. P&L is notified.
Daily-loss governor is the
5% equity drawdown cap (24h rolling). The legacy 3-loss
count cap was removed 2026-04-27 (A6) — under multi-asset it scaled linearly with
enabled assets and stopped being a meaningful governor.
Re-entry criteriapost-exit
Only opened by a volume-decay exit — meaning we
took profit on a fading move but the catalyst may still be active. The stored direction
is locked in; no news re-confirmation needed.
Opened byvolume-decay exit only
Window duration60 min
Stored directionsame as prior trade
Cooldown bypassyes (600s skip)
News check bypassyes (catalyst still live)
Re-entry triggerRT sweep or chaotic in stored dir
Sizesame as fresh entry: total_equity × size_pct%
Window closes the moment any trade is opened (re-entry or fresh). Any other exit reason
(SL, hard SL/TP, no-move) closes the window immediately — the catalyst failed.
Position sizing
Each entry is sized as total_equity × asset.size_pct / 100
— captured at entry and locked until close. Total equity = xyz perp margin + main perp
margin + spot USDC (read every 30s by equity_cache;
cache is the denominator so the wick path doesn't pay 50–150ms of REST latency on every fire).
max_concurrent_positions = 3 across all assets.
The legacy fixed-USD sizing tiers ($40/$25/$10) were retired 2026-04-26 when the bot
switched to multi-asset. The sweep that produced the V2 scale-out schedule
(25/25/25/25 @ +1/+2/+5/+10%) requires position notional ≥ $42 to keep every slice
over HL's $10 min-notional floor.
Per-instrument configuration
live from /api/assets
Per-asset wick thresholds tuned by sim_v2_threshold_sweep.py
(see memory/parameters_reference.md for source/date per row).
Most non-xyz:CL combos came from 5–9 trade samples — high variance, re-sweep weekly.
Live = real money on HL; Paper = simulated fills with 5–15 bps adverse slippage logged
to paper_trades.json.
Coin
Mode
size_pct
wick_pct
vol_ratio
CVD
Enabled
Dex
CVD column: gate = blocks counter-flow wicks
· track = subscribes to trades but doesn't gate
· off = no CVD subscription.
Recent trades
Loading…
Live ticks & candles
Ticks per minute (last 60s)
click a coin to filter tables
Ticks (AllMids)
time (UTC)
coin
mid
Candle updates (1m)
write time
candle t
coin
O
H
L
C
vol
n
Paper trades
Simulated trades on assets with paper: true.
Same wick + exit logic as live; fills include adverse slippage (5-15 bps).
No real orders are placed.
⚠️ Pre-2026-04-29 16:39 UTC trades are biased downward — vol_decay /
no_move exits were silently disabled by a deque-length bug. Trades held to SL/TP
that should have profit-exited via vol_decay. Re-score paper-asset viability using
only post-cutoff data (next 7 days = first clean window).
—
Loading…
Tradeable assets
Toggle which assets the bot is allowed to enter trades on. Changes are
written to runtime_overrides.json and
take effect within ~30s (the bot self-restarts after current positions close).
⚠ Backtest disclaimer: only xyz:CL has >7 days of
live data. Anything else is provisional — the multi-asset sim showed many
"100% WR" callouts that are pure variance on 2-4 trades. Enable cautiously.