Skip to main content

Write a strategy from scratch

A 20-line QuantScript skeleton you can paste and backtest, plus the five rules that catch most people out when writing a strategy by hand.

You do not need the agent to write QuantScript. A working strategy is short; the rules that trip people up are few.

The skeleton

StrategyParams = {
"symbol": "BTC/USDC",
"timeframe": "1h",
"rsi_length": 14,
"rsi_oversold": 30,
"base_quantity": 0.01,
}

conn = Connection.get(Connection.HYPERLIQUID, id="mock_hyperliquid")
spot = conn.get_market(Market.SPOT)


def Run():
symbol = StrategyParams["symbol"]
candles = spot.get_candles(symbol, timeframe=StrategyParams["timeframe"], limit=200)
rsi = ta.rsi(candles, length=StrategyParams["rsi_length"])

if rsi[0] < Decimal(str(StrategyParams["rsi_oversold"])) and not state.get("in_trade", False):
spot.place_order(symbol, side=Order.BUY, type=Order.MARKET,
quantity=Decimal(str(StrategyParams["base_quantity"])))
state["in_trade"] = True
log.info("bought at RSI " + rsi[0].string())

Paste this into a new strategy, validate, backtest. It buys once when RSI drops below 30 and never sells. A starting point, not advice.

The five rules that matter

  1. Only assignments and def at the top level. Settings, connection, markets, helper functions. All logic (if, for, calls) goes inside Run() or a helper.

  2. Run() exists and takes no parameters. The engine calls it every tick.

  3. Index a series before you compare it. rsi[0] > Decimal("50"), never rsi > 50. Index 0 is the newest value, -1 the oldest.

  4. Money is Decimal, built from strings. Decimal("0.01"), or Decimal(str(StrategyParams["x"])) for a setting. Never float.

  5. Remember across ticks with state, read it with .get. Plain variables inside Run() are gone when the tick ends; state survives ticks and restarts. state["k"] raises if the key is missing, state.get("k", default) does not.

Everything else (order casing, stale, what raises where) is in When a strategy does not work and in the reference.

What the platform gives you for free

  • Validation runs before every save and backtest and rejects a script with a broken rule, an unknown symbol or timeframe, or a v1 API name, with the line number and a message.

  • Backtests fund mock_hyperliquid with a simulated USDC wallet, replay 1-minute bars, match your orders against them, and record every order, log line and notification.

  • Paper and live trading run the same script; live, balances and positions come from the exchange's real-time streams (Hyperliquid today).

Did this answer your question?