← Strategy index

Strategy file: harrisScalpMM.js Market: spot

Description

Harris (2003) passive scalper with micro-profit exits and an Egginton-Van Ness-Van Ness (2016) tape-driven bid-stuffing detector. Spot.

How it works

Harris (2003) describes the 'scalping' MM archetype: a tight-spread, fast-cancel quoter that relies on depth on its side of the book to provide protection rather than on any directional forecast. The maker quotes one-tick inside the visible touch when depth on its side dominates the opposite side, then cancels immediately if the depth advantage flips. The strategy implements this as a depth-imbalance-gated quoter: it only joins the queue when bid_depth / ask_depth exceeds a threshold for buys, and the inverse for sells. Profitable only on venues where queue priority earns rebates or tight effective spreads.

Capital & Period

Order sizing and candle timeframe.

Key Type Default Description
PERIOD select 5 Candle timeframe Gunbot feeds the strategy. 1-3 min suits very liquid spot or perp; 5 min is the balanced default; 15 min reduces noise on thinner pairs at the cost of slower adaptation.
TRADING_LIMIT range (range 10..5000) 100 Order size in QUOTE currency (e.g. USDT) per buy attempt. Sets per-quote notional; raise to commit more per fill, lower to keep risk smaller per trade. Spot: TL is the quote amount per entry bid. Smaller TL = more, smaller fills.
HS_TL range (range 10..5000) 100 Strategy-specific TL override. When set, takes precedence over TRADING_LIMIT for THIS strategy only — lets you run different sizes per pair from the GUI without touching the global TL.
HS_CAPITAL_ALLOC range (range 100..100000) 2000 Hard cap on capital this strategy is allowed to commit on this pair. Drives circuit breakers (daily-loss = % of this) and exposure math. Set to the maximum quote balance you want this pair to ever consume.

Allocation

How much of THIS pair’s wallet the strategy may use, what it must start with, and the hard config gate. Trading is BLOCKED until Wallet allocation % is set AND Allocation confirmed is ON. Optional grid splits an order into laddered post-only rungs for better fills.

Key Type Default Description
ALLOC_PCT range (range 1..100) 25 Percentage of THIS pair’s wallet balance the strategy may deploy. Effective cap = min(wallet × this %, the absolute Capital allocation). Every order is clamped to it and can never exceed it. REQUIRED — trading is blocked until this is set (>0) and Allocation confirmed is ON.
ALLOC_CONFIRMED boolean False Explicit acknowledgement that the allocation above is correct for this pair. The strategy will NOT place any entry order until this is ON. A clear "ALLOCATION CONFIGURED" line is logged once it is; otherwise an "ALLOCATION NOT CONFIGURED — refusing to trade" line is logged each cycle.
ALLOC_SPLIT_TOL range (range 0..100) 15 How far the starting base/quote split may deviate from what this strategy needs before it refuses to start. Long-only strategies want mostly quote/cash; two-sided market-makers want ~50/50 base/quote; futures want free margin. Mismatch beyond this % blocks trading (unless Enforce start inventory is OFF).
ALLOC_ENFORCE_SPLIT boolean True When ON, the strategy refuses to trade until the starting base/quote split is within tolerance of what it needs (archetype-aware). When OFF, a mismatch is logged as a warning but trading proceeds.
ALLOC_AUTO_REBALANCE boolean True Two-sided market-makers only. ON by default: if the pair starts off the target base/quote split, the strategy places a single bounded market order on start to reach it (e.g. buys ~half the allocation into base for a 50/50 maker), then begins normal trading. Set to OFF to instead stay blocked and log the exact amount to buy/sell manually. Long-only and futures strategies ignore this.
ALLOC_RESERVE_PCT range (range 0..50) 0 A buffer, as % of wallet, kept BELOW the allocation cap and never deployed. Use to leave headroom for fees/slippage. Effective cap = min(wallet × allocation %, absolute cap) − wallet × this %.
HS_GRID boolean False When ON, an entry order is split into several laddered post-only rungs across a price band instead of one order — often gets better average fills. Cumulative size is still clamped to the allocation. OFF = single order.
HS_GRID_LEVELS range (range 2..10) 3 Number of laddered rungs to split an entry into when "Split entries into a grid" is ON. More rungs = finer fills but more orders.
HS_GRID_SPAN_PCT range (range 0.1..5) 0.5 Price band width, as % from the reference price, across which the grid rungs are spread. e.g. 0.5 places rungs from the reference price down to 0.5% below it (for buys).

Scalping

Entry depth, micro-profit exit target and exit-slide schedule.

Key Type Default Description
HS_ENTRY_DEPTH range (range 1..50) 5 How far below mid the passive bid is posted. Deeper = lower fill rate but better entry price. 5 bps suits 1m BTC/USDT; raise on lower-volatility pairs where the bid would otherwise sit too close.
HS_MICRO_BPS range (range 1..50) 4 Bps above break-even at which the immediate post-entry sell is posted. 4 bps gives roughly 1.5x fees coverage on Binance retail. Higher = waits for fatter profits; lower = scratches faster (lower expectancy per trade).
HS_MICRO_STALE range (range 1..200) 12 After this many cycles holding the position, the exit price begins sliding linearly DOWN toward break-even. Earlier = quicker concession to give up the micro target; later = patient about achieving full micro-profit.
HS_MAX_STALE range (range 5..500) 40 Hard cap on hold cycles. When reached, the exit collapses to BE + fee cushion and exits at market on the next favourable bid. BE_GUARD ensures this never realises a loss when enabled.
HS_MAX_EXP range (range 10..95) 60 Maximum portion of pair equity in the quote (target) asset. Above this, no new bids are posted. Lower to keep more dry-powder; higher to compound faster at the cost of less liquidity buffer.

Stuffing Detector (live tape)

Egginton, Van Ness & Van Ness (2016) burst-rate + small-trade-size signature, computed from the live trade tape.

Key Type Default Description
HS_USE_TAPE boolean False When ON, pulls real trades from the shared tape and detects burst-stuffing via Poisson z-score and median-trade-size collapse. When OFF the detector is disabled (no false-positive heuristic). Recommended ON for Bybit/Binance/Kraken/OKX where the tape feed is available.
HS_BURST_WINDOW_MS range (range 500..10000) 2000 Recent trades window in which a burst is measured. Shorter = catches sharper bursts; longer = smoother but missier on fast bursts.
HS_BASELINE_WINDOW_MS range (range 10000..600000) 60000 Longer window used as the "normal" reference rate and median trade size. Larger = more stable baseline at the cost of slower adaptation to regime shifts.
HS_BURST_Z range (range 1..6) 3 Burst rate must exceed baseline by this many standard deviations (Poisson model) to count toward stuffing. 3.0 ≈ 0.13% false-positive rate per evaluation. Lower for hair-trigger; higher for very conservative.
HS_BURST_SIZE_FRAC range (range 0.1..1) 0.4 Burst median trade size must be BELOW this fraction of baseline median to flag stuffing (small-message signature per Egginton 2016). Lower = stricter (requires more obviously tiny bursts); higher = more permissive.
HS_BURST_MIN_TRADES range (range 3..100) 8 Minimum number of trades inside the burst window before the test fires — avoids statistical noise on near-empty windows. Raise on illiquid pairs.
HS_STUFFING_COOL range (range 1..200) 10 After a stuffing detection, the strategy cancels working orders and refuses to post new orders for this many cycles.

Rebates & Display

Maker-rebate accounting (most spot exchanges are 0) and sidebar precision.

Key Type Default Description
HS_MAKER_REBATE range (range -2..5) 0 Per-side maker rebate (bps). Sidebar-only. Most spot exchanges run zero maker rebate; set if your venue offers one (e.g. Coinbase Pro tier-3 +0.05%).
HS_SP range (range 0..8) 6 Decimal places shown for prices in the sidebar. 6 suits low-priced spot tokens.
HS_STALE_CYCLES range (range 1..60) 5 How long a working entry bid may sit before being cancelled and re-posted at a fresh mid-relative price.

Runtime & Exchange

Logging, fees and the cross-exchange/safety toggles.

Key Type Default Description
LOG_LEVEL select NORMAL Controls how much the strategy writes to Gunbot logs. SILENT keeps only errors and circuit-breaker messages. NORMAL writes one summary line per cycle plus order events — recommended for live trading. DEBUG adds full internal model state.
WARMUP_CYCLES range (range 1..60) 5 Cycles to wait before the strategy starts placing orders. Lets candle history, OU/ADF fits, and tape caches reach a stable estimate. 5 is fine on liquid pairs; raise to 15-30 on illiquid pairs or longer candle periods.
HS_FEE range (range 0..0.2) 0.1 Taker fee for your exchange tier, as a percentage. Used in P&L bookkeeping and fee-aware exit-price math. Pull the exact number from your exchange fee schedule (VIP/maker tier) for accurate fees.
HS_MAX_DD range (range 1..30) 10 Peak-to-trough equity drawdown that pauses the strategy. Hits → strategy stops placing new orders until manual reset. Tighter (3-5%) for conservative, wider (10-20%) for higher-risk venues.
HS_MAX_EXP range (range 10..95) 60 Hard cap on capital deployed at any moment. Above this, new entry orders are blocked. Lower = more idle cash buffer; higher = more capital working but tighter liquidation risk on futures.
HS_DAILY_LOSS range (range 0.5..10) 2 Daily loss budget as a % of CAPITAL_ALLOC. When today's PnL falls below this threshold, the strategy halts for the remainder of the UTC day. Resets at next-day rollover.
BE_GUARD boolean True When ON, blocks any sell/close at a price BELOW the position break-even while holding a long. Wraps sellMarket, sellLimit, sellLimitPostOnly, closeMarket and closeLimit. Set false to disable (e.g. when you intentionally allow stop-loss exits below BE).
NO_POST_ONLY boolean False When ON, every post-only order is routed as a regular limit order instead. Auto-enabled for PancakeSwap and Aster (DEXes with no post-only flag). Turn ON manually for any exchange that rejects post-only with an error in your logs.
NO_CLOSE_MARKET boolean False When ON, position closes are routed through opposite-side market orders instead of closeMarket(). Auto-enabled when closeMarket is unavailable in the runtime. Use only if your exchange/build does not implement the close API.
HS_TRACE boolean False When ON, writes a structured JSONL audit trail to gunbot_logs/quantroduction/-.jsonl AND echoes every gate, compute, quote, order and fill decision to the main console log. Useful for verifying literature fidelity, debugging mis-fills and post-hoc analysis of strategy behaviour. Default OFF (zero overhead).
VERBOSE_LOGS boolean False When ON, the full Quantroduction × Gunbot dashboard (every config value + state snapshot) re-emits every VERBOSE_INTERVAL_MIN minutes for forensic audit. When OFF (default), the dashboard only fires once per Gunbot restart per pair.
VERBOSE_INTERVAL_MIN range (range 5..240) 30 How often the dashboard re-emits when VERBOSE_LOGS is ON. Lower = more frequent / noisier; higher = quieter. Has no effect when VERBOSE_LOGS is OFF.
BE_GUARD_BLOCK_MARKET_SELLS boolean True Default ON (legacy). Set OFF to enable SOFT BE_GUARD: market sells and closeMarket pass through (treated as urgent / stop-loss). Only limit sells below break-even remain blocked. Prevents BE_GUARD from silently swallowing stop-loss exits.
SCRATCH_LIVENESS_MIN range (range 0..120) 0 When >0: if the pair holds inventory and hasn't filled in N minutes AND the bid is at break-even+1bp, force a market exit to rotate capital. 0 = disabled. Typical: 30.
CONSEC_RESET_CYCLES range (range 60..2880) 480 After this many cycles without any order activity, auto-reset consecutiveLosses to 0. Default 480 cycles ≈ 2h at 15s/cycle. Prevents a 3-loss streak from killing the pair for the entire session.
DRIFT_ATR_FRAC range (range 0..0.5) 0 When >0: scale drift-requote threshold to this fraction of the recent 10-candle high-low range (clamped 2-100 bps). 0 = use fixed *_STALE_DRIFT_BPS. Typical: 0.05 = 5% of recent range. Adapts drift detection to per-pair volatility.
SKEW_QTY_MAX range (range 1..5) 2.5 Maximum ask:bid qty ratio when inventory is heavily skewed. 2.5 means a heavily-bagged pair quotes up to 2.5x ask qty vs bid qty to drain inventory faster. Set 1.0 to disable (symmetric quoting).
SKEW_QTY_TARGET range (range 0.1..0.9) 0.5 Target inventory fraction of pair equity. 0.5 = 50/50 balanced base/quote. Skew kicks in proportionally as actual exposure deviates from target.
PORTFOLIO_INCLUDE boolean True When ON (default), this pair participates in the shared PORTFOLIO_EXP_BUDGET — its exposure counts toward portfolio total and bids pause when budget is exceeded. When OFF, the pair stands alone (use PAIR_EXP_BUDGET for own cap).
PORTFOLIO_EXP_BUDGET range (range 0..1) 0 Cap on total portfolio inventory as fraction of total allocated equity (sum across PORTFOLIO_INCLUDE pairs). 0 = disabled. Typical: 0.6 = 60% inventory cap across the included portfolio. When exceeded, bids pause but exits remain active.
PAIR_EXP_BUDGET range (range 0..1) 0 This pair's own exposure cap as fraction of pair equity (inventory / pair allocated capital). Applies independently of portfolio budget. 0 = disabled. Typical: 0.2 = 20% per-pair cap.
DISABLE_BREAKER_WINDDOWN boolean False When OFF (default), an active breaker (3 consecutive losses or daily loss limit) actively frees capital: cancels open orders and scratch-sells inventory IF profitable (bid >= BE+1bp). When ON, legacy halt-and-hold behaviour.
TRACE_ALL boolean False Master switch for the Quantroduction tracer. When ON, writes detailed per-cycle JSONL to gunbot_logs/quantroduction/ AND emits a verbose console summary. Equivalent to setting every _TRACE to true. Useful for diagnosing silent gates and breakers. Disk overhead ~1MB/day/pair.

Safety & Tuning (v1.0-beta)

Universal safety + tuning knobs added in v1.0-beta. These were previously hidden from the chart page even though the strategy reads them. Setting any of these here will be applied per-pair.

Key Type Default Description
HS_CONSEC_LOSSES_LIMIT range (range 1..20) 5 Number of consecutive losses that trips the circuit breaker for HarrisScalpMM specifically. Default 5 (higher than the universal default of 3 because HS makes many small trades). After this many losses the strategy pauses until cooldown clears.
HS_PERIOD string 1 Candle period in minutes used for this strategy's indicators. Common values: '1', '5', '15'. Some strategies need a long history to warm up indicators.
MIN_ORDER_QUOTE range (range 1..100) 5 Floor on order size in quote currency to avoid exchange dust rejections. Match to your exchange's minimum notional. Default 5 USDT.
STRICT_LITERATURE boolean False Master switch. When ON, the strategy disables every operator-grade safety override (BE_GUARD, cross-protection floors, BE ask clamps, drift-ATR scaling, asymmetric sizing, scratch liveness, breaker wind-down) so it runs as faithful as we can make it to the cited academic paper. Use this for paper-comparison backtests or academic research. WARNING: in strict mode the strategy can take real losses (papers prove optimality only in expectation, not per-trade).
NO_CLOSE_MARKET toggle False When true, the strategy NEVER falls back to a market sell to close a held inventory — only post-only limits. Use to prevent any taker fee on exits. Default false (allow market close when necessary).
QUANTRODUCTION_TRACE toggle False When true, this single pair writes detailed cycle events to gunbot_logs/quantroduction/-.jsonl. Use TRACE_ALL to enable across all pairs at once; this knob overrides per-pair. Default false.
RESET_BREAKER_ONCE toggle False One-shot: set true and Gunbot will clear all tripped risk breakers (consec_losses, daily_loss, max_dd) on this pair on the next cycle, then re-arm them. The setting auto-clears itself after firing. Use when a breaker tripped on a now-stale condition.
RESET_STATS_ONCE toggle False One-shot: set true and Gunbot will clear customStratStore counters (wins, losses, totalPnL, peakEquity, maxDD, dailyPnL, dailyLossLimit) on this pair on the next cycle. The setting auto-clears itself after firing. Useful after a recovery / regime change.

Portfolio & Runtime (per-pair overrides)

Per-pair runtime knobs. Override any of these on a single pair without changing the strategy defaults.

Key Type Default Description
SPREAD_PNL_JUMP_GUARD range (range 0.1..1) 0.5 Realized-PnL deltas larger than this fraction of pair equity are treated as deposits/withdrawals/data-glitches and skipped. Default 0.5 means a single delta over 50% of equity is ignored. Lower for tighter glitch detection on small accounts.

References & further reading

Configuration playbook