Appearance

Personalize your experience

Mode
Accent Color
Direction
MarketplacestrategiesSpectral Cycle Timing
QuaScript

Spectral Cycle Timing

Free

Buys cycle troughs, sells crests while a cycle is locked

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
quascriptstrategycyclestimingspectrum
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.

Spectral Cycle Timingengine 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

Times entries with the market's dominant cycle. Complex demodulation measures power at 16 cycle lengths; when one length clearly dominates (a cycle lock), the phase of that cycle tells where price sits in it. The strategy buys cycle troughs and sells cycle crests in the direction of the slower trend, and leaves when half a cycle has passed. Entry: cycle lock, the detrended cycle wave turning up from below zero (trough) with price above the trend EMA, or down from above zero (crest) with price below it. Exit: half the dominant period, an ATR stop, or a target at the cycle amplitude. Risk: 1 % per trade. Method: complex demodulation (Bloomfield, 1976).


Settings

Demodulation smoothing: 48

Shortest period: 10

Period step: 3

Lock share: 0.14

Trend EMA: 150

Stop (ATR): 2


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

  • ▸ cycle lock, the detrended cycle wave turning up from below zero (trough) with price above the trend EMA, or down from above zero (crest) with price below it

Exit Conditions

  • ▸ half the dominant period, an ATR stop, or a target at the cycle amplitude

Measured backtest

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

Backtest this strategy

-24.0%

Return

-2.51

Sharpe

-25.3%

Max DD

37.9%

Win Rate

116

Trades

MarketTradesReturnSharpeMax DDWin rateProfit factor
BTCUSDT 1h116-24.0%-2.51-25.3%37.9%0.57
ETHUSDT 1h171-13.5%-1.06-20.5%49.1%0.82

Past results on historical data do not predict future returns.

Source Code

Edit in IDE
quascript
1strategy "Spectral Cycle Timing" {
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/// Times entries with the market's dominant cycle. Complex demodulation measures power at 16 cycle
12/// lengths; when one length clearly dominates (a cycle lock), the phase of that cycle tells where
13/// price sits in it. The strategy buys cycle troughs and sells cycle crests in the direction of
14/// the slower trend, and leaves when half a cycle has passed.
15/// Entry: cycle lock, the detrended cycle wave turning up from below zero (trough) with price above
16/// the trend EMA, or down from above zero (crest) with price below it. Exit: half the dominant
17/// period, an ATR stop, or a target at the cycle amplitude. Risk: 1 % per trade.
18/// Method: complex demodulation (Bloomfield, 1976).
19use "viz/premium" as pr
20smooth = param.int(48, title = "Demodulation smoothing", min = 8, max = 400, group = "Spectrum")
21p_min = param.int(10, title = "Shortest period", min = 4, max = 80, group = "Spectrum")
22p_step = param.int(3, title = "Period step", min = 1, max = 20, group = "Spectrum")
23lock = param.float(0.14, title = "Lock share", min = 0.07, max = 0.5, step = 0.01, group = "Spectrum")
24trend = param.int(150, title = "Trend EMA", min = 20, max = 1000, group = "Trend")
25stop_k = param.float(2.0, title = "Stop (ATR)", min = 0.5, max = 8, step = 0.1, group = "Risk")
26x = close - ta.sma(close, smooth)
27best = 0.0
28best_k = 0
29total = 0.0
30for k in 0..=15 {
31 per = p_min + k * p_step
32 ang = 2 * math.pi * bar.index / per
33 re = ta.ema(x * math.cos(ang), smooth)
34 im = ta.ema(x * math.sin(ang), smooth)
35 p = math.coalesce(re * re + im * im, 0)
36 total := total + p
37 if p > best {
38 best := p
39 best_k := k
40 }
41}
42share = total > 0 ? best / total : 0
43period = p_min + best_k * p_step
44// the cycle wave: price detrended over 20 bars and smoothed over 5, read against the locked cycle
45wave = ta.ema(close - ta.sma(close, 20), 5)
46t = ta.ema(close, trend)
47a = ta.atr(20)
48locked = share >= lock
49trough = locked and wave[1] < wave[2] and wave > wave[1] and wave < 0
50crest = locked and wave[1] > wave[2] and wave < wave[1] and wave > 0
51flat = position.size == 0
52if flat and trough and close > t {
53 order.market("L", side.long)
54 exit.bracket("L exit", entry = "L", stop = close - stop_k * a, target = close + 2 * math.abs(wave) + a)
55}
56if flat and crest and close < t {
57 order.market("S", side.short)
58 exit.bracket("S exit", entry = "S", stop = close + stop_k * a, target = close - 2 * math.abs(wave) - a)
59}
60persist half = 10
61if flat { half := math.max(math.round(period / 2), 3) }
62if position.size != 0 and position.bars_held >= half { exit.close_all() }
63risk.max_drawdown(25)
64render.line(t, "Trend EMA", color = color.amber.300, width = 1.5)
65render.mark(trough and close > t, shape = shape.circle, at = anchor.below_bar, color = color.cyan.300, size = 0.6, title = "Cycle trough")
66render.mark(crest and close < t, shape = shape.circle, at = anchor.above_bar, color = color.fuchsia.300, size = 0.6, title = "Cycle crest")
67persist tb = draw.table.create(anchor.top_right, 5, 2)
68if bar.is_last {
69 pr.heading(tb, 2, "Spectral Cycle Timing", "Strategy · dominant-cycle entries")
70 pr.row(tb, 2, "Dominant period", str.format("{} bars", period), color.white)
71 pr.row(tb, 3, "Power share", str.format("{:.0%}", share), locked ? pr.BULL : pr.LABEL)
72 pr.row(tb, 4, "Phase", wave > 0 ? "Upper half" : "Lower half", color.white)
73}
74 
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.