Appearance

Personalize your experience

Mode
Accent Color
Direction
MarketplacestrategiesHawkes Shock Reversal
QuaScript

Hawkes Shock Reversal

Admin's ChoiceFree

Buys the end of a selling cascade, sells the end of a frenzy

0.0(0)
0 installs 0 0 comments
Q
159 listings

The QuaTick team's QuaScript analyses, run by the native C++ engine.

View Profile
quascriptstrategyreversalhawkesshocks
Free
Backtest this strategy Open in QuaTick IDE Edit in IDE
Version
Updated
Compatible

Live engine preview

QuaScriptQuaScript

The QuaScript engine's own output on the chart the terminal uses. Change the settings or edit the code and press Run to recompute it.

Hawkes Shock Reversalengine result
Loading the engine result…
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

About

Buys the end of a selling cascade and sells the end of a buying frenzy. Large moves are counted as events in a self-exciting Hawkes process, so clusters build intensity and the intensity then decays. When a cluster of down shocks has decayed (calm returning) and price closes back above a short mean, the forced selling is likely done. Entry: down-shock intensity peaked above the cluster level and has since decayed below the calm level, close above the 10-bar EMA (mirror for shorts). Exit: stop below the cascade low, target `reward` R, time stop. Risk: 1 % per trade. Method: Hawkes (1971).


Settings

Volatility window: 100

Shock size (sigma): 2

Decay per bar: 0.12

Cluster level: 1.2

Calm level: 0.3

Target (R): 2

Maximum bars held: 48


Measured backtests

Run by the backtest engine on public candles, 2025-11-01 to 2026-11-01, with the script's own commission and slippage, on BTCUSDT 1h (Binance) and ETHUSDT 1h (Binance). The figures per market are in the Measured backtest panel below. Past results do not predict future returns.


Backtest it yourself

Open it on the backtesting page to run it on any symbol, interval and date range, then use Monte Carlo, optimisation, walk-forward and robustness tests.

Strategy Rules

Entry Conditions

  • ▸ down-shock intensity peaked above the cluster level and has since decayed below the calm level, close above the 10-bar EMA (mirror for shorts)

Exit Conditions

  • ▸ stop below the cascade low, target `reward` R, time stop

Measured backtest

BTCUSDT 1h (Binance), 2025-11-01 to 2026-11-01 · backtest engine, script costs included

Backtest this strategy

1.2%

Return

0.16

Sharpe

-10.1%

Max DD

41.4%

Win Rate

116

Trades

MarketTradesReturnSharpeMax DDWin rateProfit factor
BTCUSDT 1h1161.2%0.16-10.1%41.4%1.02
ETHUSDT 1h11218.3%1.40-7.3%43.8%1.31

Past results on historical data do not predict future returns.

Source Code

Edit in IDE
quascript
1strategy "Hawkes Shock Reversal" {
2 overlay = true
3 capital = 100000
4 commission = 0.05
5 slippage = 1
6 sizing = risk_percent
7 max_leverage = 1
8 size = 1
9 pyramiding = 1
10}
11/// Buys the end of a selling cascade and sells the end of a buying frenzy. Large moves are counted
12/// as events in a self-exciting Hawkes process, so clusters build intensity and the intensity then
13/// decays. When a cluster of down shocks has decayed (calm returning) and price closes back above
14/// a short mean, the forced selling is likely done.
15/// Entry: down-shock intensity peaked above the cluster level and has since decayed below the calm
16/// level, close above the 10-bar EMA (mirror for shorts). Exit: stop below the cascade low, target
17/// `reward` R, time stop. Risk: 1 % per trade. Method: Hawkes (1971).
18use "viz/premium" as pr
19len = param.int(100, title = "Volatility window", min = 20, max = 2000, group = "Shocks")
20k_sd = param.float(2.0, title = "Shock size (sigma)", min = 1, max = 5, step = 0.1, group = "Shocks")
21decay = param.float(0.12, title = "Decay per bar", min = 0.01, max = 0.8, step = 0.01, group = "Process")
22hot = param.float(1.2, title = "Cluster level", min = 0.2, max = 10, step = 0.1, group = "Signals")
23calm = param.float(0.3, title = "Calm level", min = 0.01, max = 5, step = 0.01, group = "Signals")
24reward = param.float(2.0, title = "Target (R)", min = 0.5, max = 10, step = 0.1, group = "Risk")
25hold = param.int(48, title = "Maximum bars held", min = 2, max = 500, group = "Risk")
26r = math.log(close / close[1])
27sd_now = stat.stdev(r, len)
28sd = sd_now[1]
29lam_d = hft.hawkes(r < -k_sd * sd, decay, 1)
30lam_u = hft.hawkes(r > k_sd * sd, decay, 1)
31e10 = ta.ema(close, 10)
32low20 = ta.lowest(low, 20)
33high20 = ta.highest(high, 20)
34persist armed_l = false
35persist armed_s = false
36if lam_d > hot { armed_l := true }
37if lam_u > hot { armed_s := true }
38flat = position.size == 0
39go_l = armed_l and lam_d < calm and close > e10
40go_s = armed_s and lam_u < calm and close < e10
41if flat and go_l {
42 order.market("L", side.long)
43 exit.bracket("L exit", entry = "L", stop = low20, target = close + (close - low20) * reward)
44 armed_l := false
45}
46if flat and go_s {
47 order.market("S", side.short)
48 exit.bracket("S exit", entry = "S", stop = high20, target = close - (high20 - close) * reward)
49 armed_s := false
50}
51if position.size != 0 and position.bars_held >= hold { exit.close_all() }
52risk.max_drawdown(25)
53render.line(e10, "10-bar EMA", color = color.slate.300, width = 1)
54render.mark(lam_d > hot and lam_d[1] <= hot, shape = shape.x, at = anchor.below_bar, color = color.rose.400, size = 0.6, title = "Selling cascade")
55render.mark(lam_u > hot and lam_u[1] <= hot, shape = shape.x, at = anchor.above_bar, color = color.emerald.400, size = 0.6, title = "Buying frenzy")
56render.mark(go_l and flat, shape = shape.triangle_up, at = anchor.below_bar, color = color.sky.300, text = "Calm", title = "Long after cascade")
57render.mark(go_s and flat, shape = shape.triangle_down, at = anchor.above_bar, color = color.amber.300, text = "Calm", title = "Short after frenzy")
58persist t = draw.table.create(anchor.top_right, 4, 2)
59if bar.is_last {
60 pr.heading(t, 2, "Hawkes Shock Reversal", "Strategy · self-exciting shocks")
61 pr.row(t, 2, "Down / up intensity", str.format("{:.2f} / {:.2f}", lam_d, lam_u), color.white)
62 pr.row(t, 3, "Armed", armed_l ? "Long" : armed_s ? "Short" : "No", armed_l ? pr.BULL : armed_s ? pr.BEAR : pr.LABEL)
63}
64 
Read-only preview. Open in the QuaTick IDE to edit and deploy.

Reviews

No reviews yet. Be the first to review this listing.

Discussion

Sign in to join the discussion. Your posts and replies show up on your profile.