Ultimate Simulation
STOCK GAME is a real-time trading simulator designed to teach price action, indicators, and execution flow.
Build your own indicator formulas and connect them directly to automated trading logic.
Histogram + curve follow live engine ticks and your pressure settings. To adjust, go to Pressure Lab.
All indicator and auto-trade variables are listed below. The Custom Indicator panel expects price-scale outputs.
t: normalized bar position (0-1)i: bar indextime: bar timestamp bucketopen, high, low, close, volprevOpen, prevHigh, prevLow, prevClose, prevVolprev2Open, prev2High, prev2Low, prev2Close, prev2Volrange, rangePct, body, bodyPct, bodyDirisBull, isBear, isDojigap, gapPct, gapDirupperWick, lowerWick, upperWickPct, lowerWickPcthlRangePct, closePos, hl2, hlc3, ohlc4, typicalchange, changePct, logReturn, trueRangeatr7, atr14, atr21, atrPctsma5, sma10, sma20, sma50, sma100ema5, ema10, ema20, ema50, ema100smaDiff, emaDiff, ema10Slope, sma20SlopepriceAboveSma20, priceAboveEma20, trendUprsi7, rsi14, rsi21, rsiSloperoc12, stochK, stochDmacdLine, macdSignal, macdHistvwap, obv, closeAboveVwapvolSma5, volSma20, volSma50, volChange, volChangePct, volRelbbUpper, bbMiddle, bbLower, bbWidth, bbPctBdata, opens, highs, lows, closes, volssma, ema, highest, lowest, sum, avg, stdbalance, holdings, avgPrice, priceequity, pnl, returnRate, positionValuelastTrade: { type, price, qty, time }orderQty, setOrderQty(qty)buyOrderQty(), sellOrderQty()buy(qty), sell(qty), hold()buyMarket(qty), sellMarket(qty)buyLimit(price, qty), sellLimit(price, qty)buyStop(stop, qty, limitPrice?), sellStop(stop, qty, limitPrice?)buyPct(pct), sellPct(pct)buyValue(amount), sellValue(amount)riskQty({ riskPct, stopPct, price, equityValue })cooldown(key, ms): true when allowed, then sets timeroncePerBar(key): true once per candle indexmem: persistent memory objectctx: { now, barIndex, barTime, tick, mem }Market orders execute immediately at the current price. Limit orders are reserved and fill only when price crosses the limit; filled limit/stop orders show a (LIMIT)/(STOP) tag in the trade log and a toast notification.
// Manual buttons: BUY MKT / SELL MKT / BUY LIMIT / SELL LIMIT
// Auto-trade example:
if (rsi14 < 30) buyMarket(3);
if (holdings > 0 && rsi14 > 70) sellLimit(price * 1.01, 2);
Tip: Use mem to store strategy state (e.g., mem.mode = 'trend').
// Example (advanced auto trade)
if (oncePerBar('entry') && cooldown('rsi', 4000) && rsi14 < 30 && trendUp > 0) {
const qty = riskQty({ riskPct: 1, stopPct: 1.5 });
if (qty > 0) buy(qty);
}
if (holdings > 0 && (macdHist < 0 || priceAboveEma20 === 0)) {
sellPct(50);
}
if (!mem.lastTick) mem.lastTick = ctx.tick;
// Example (order types)
// Enter on breakout, then protect with stop or stop-limit.
if (oncePerBar('entry') && cooldown('brk', 3000) && closeAboveVwap === 1) {
buyStop(price * 1.01, 5);
}
// Scale out using a limit if price stretches.
if (holdings > 0 && rsi14 > 70) {
sellLimit(price * 1.02, 3);
}
// Optional: stop-limit instead of stop-market
if (holdings > 0 && rsi14 < 45) {
sellStop(price * 0.985, 5, price * 0.98);
}
If anything is unclear, see the coding examples module.
Saved coding config auto-loads in Trading Terminal.
return to output a value.if, for, while.
return sma10 - sma20;return close - vwap;
Use inside the Indicator Code editor.
Full variable list and advanced examples are documented in Quick Reference.
open, high, low, close, volprevOpen, prevHigh, prevLow, prevClose, prevVolprev2Open, prev2High, prev2Low, prev2Close, prev2Voli (index), t (0-1)range, body, bodyPct, bodyDirupperWick, lowerWick, gap, gapPcthl2, hlc3, ohlc4, hlRangePctchange, changePct, logReturn, trueRangesma5, sma10, sma20, ema5, ema10, ema20smaDiff, emaDiff, rsi14, rsiSlope, atr14obv, vwap, roc12, stochK, stochDvolSma20, volChange, volChangePct, closeAboveVwap, trendUp// Example: plot a custom momentum blend
return (rsi14 - 50) + (ema10 - ema20);
If anything is unclear, see the coding examples module.
Saved coding config auto-loads in Trading Terminal.
buy(), sell(), hold(), or advanced order helpers.
Use inside the Auto Trading editor.
Full helper list and strategy examples are in Quick Reference.
orderQty, setOrderQty(qty)buyOrderQty(), sellOrderQty()buyMarket(qty), sellMarket(qty)buyLimit(price, qty), sellLimit(price, qty)buyStop(stop, qty, limitPrice?), sellStop(stop, qty, limitPrice?)// Example: simple oversold buy, overbought sell
if (Number.isFinite(rsi14) && rsi14 < 30 && balance > close * 3) {
buy(3);
}
if (Number.isFinite(rsi14) && rsi14 > 70 && holdings > 0) {
sell(Math.min(3, holdings));
}
t (0-1 loop), i (bar index), price, vol, changePct, Math.Deep Dive into Order Flow, Indicators, and Strategy Design
Stock Game Pro is a market?microstructure simulator where every candle is produced by order-book depletion. The price does not move randomly; it moves because bids or asks are consumed. This gives you a clean environment to learn how real price discovery works.
Core loop: order-book pressure -> price tick -> candle update -> indicator update -> strategy decision.
Goal: train your eye to link the flow (orders) to the response (price + indicators).
Every candle is built from simulated market buys/sells depleting the order book. This shows why price moves rather than just the result.
Indicators (RSI, MACD, VWAP, BB, ATR, ADX, MFI, etc.) update on each tick, so you see their true behavior during live price formation.
Write your own formulas and render them directly on the chart. This is ideal for testing ideas quickly without external tools.
Test entry/exit logic with advanced helper functions (market, limit, stop, sizing, cooldowns). You can iterate safely and observe results immediately.
Learning benefit: You can isolate one skill at a time?trend reading, momentum timing, volatility control, and execution precision?then combine them into a complete strategy.
Why it matters: Most charts only show outcomes. This simulator shows causes, which is exactly what you need to improve decision-making.
Scalping is more than just fast trading; it is the process of understanding Market Microstructure. This simulator demonstrates how raw order book data is transformed into candles and technical indicators in real-time.
Why this simulator is different: You are not just watching random candles. Every tick is born from order book depletion, so you can see why price moves, not just that it moves.
Key strengths: practice reading liquidity shifts, test strategies with real-time indicators, and build your own indicators and automated rules without external tools.
Watch bids/asks: thick levels act like magnets or barriers. When a level is fully consumed, price ticks to the next level.
Use trend indicators (SMA/EMA/VWAP) for direction, momentum indicators (RSI/MACD/Stoch) for timing, and volatility (ATR/BB) for risk.
Test manual or automated rules. Use limit orders for better fills, stop orders for protection, and helper functions for sizing.
After each run, check the trade log and indicator behavior. Adjust one rule at a time so you can see exactly what improved or worsened your results.
When market buy orders consume the entire liquidity at the Best Ask, price ticks upward to the next level.
When market sell orders deplete the Best Bid, price ticks downward to find new buyers.
Benefit: You learn how bids and asks absorb orders and why breakouts or reversals happen at specific price levels. This builds intuition that classic charts alone can't teach.
Instant execution at the current price. Use when speed is more important than price.
Reserved orders that only fill if price crosses your limit. Use for precise entries and exits.
Protective orders that trigger when price crosses a level. Stop?limit adds price control after the trigger.
Use orderQty to read the UI quantity, setOrderQty to change it, and riskQty to size by risk. This keeps your execution consistent and prevents accidental oversizing.
The indicators below are mathematical re-renderings of the trade data generated in the order book. Use overlays to guide trend direction, oscillators to gauge momentum, and volume tools to confirm participation.
SMA smooths price by averaging the last N closes. It shows the underlying trend and common support/resistance zones.
EMA weights recent prices more heavily, reacting faster to new order flow than SMA.
BB measure volatility around a moving average. Expanding bands = rising volatility; contracting bands = compression.
VWAP blends price and volume to show the average price where most volume traded.
RSI is a momentum indicator that measures the magnitude of recent price changes to evaluate overbought or oversold conditions.
MACD measures trend strength by comparing fast and slow EMAs, then smoothing with a signal line.
Stochastic compares the current close to the recent high-low range to detect momentum shifts.
CCI measures deviation from a moving average using typical price to spot cyclic turns.
ADX shows trend strength, regardless of direction. Higher values mean stronger, more directional moves.
ATR measures volatility by tracking the average true range of recent candles.
MFI blends price and volume to measure buying vs selling pressure.
ROC measures speed of price change over a set period.
Williams %R is a momentum oscillator scaled between -100 and 0, similar to Stochastic.
Volume bars show how much participation occurred during each candle.
OBV accumulates volume based on price direction, revealing whether volume supports the trend.
These are secondary metrics available in the custom indicator and auto-trade engines. They are not plotted by default but are powerful for filtering, confirmation, and risk control.
Fast and slow RSI versions plus the direction of RSI change. Use rsi7 for quick turns, rsi21 for trend context, and rsiSlope to detect momentum acceleration.
Short and long volatility baselines. atrPct expresses ATR as a % of price, useful for dynamic sizing and setting realistic targets.
smaDiff, emaDiff, ema10Slope, and sma20Slope capture spread and acceleration between averages. Great for early trend shifts.
In addition to MACD line, you can monitor macdSignal and macdHist to confirm whether momentum is building or fading.
The smoothed line (stochD) helps filter noisy %K spikes. Crosses of %K and %D often precede micro reversals.
bbWidth measures squeeze/expansion, while bbPctB shows where price sits inside the bands (0 to 1).
volSma5/20/50, volRel, and volChangePct quantify whether current volume is above normal and how fast it is changing.
priceAboveSma20, priceAboveEma20, closeAboveVwap, and trendUp provide quick regime checks for filters and stop logic.
The auto-trading engine can read and control the UI order size directly. This lets you size trades dynamically without hard-coding a quantity.
Pro Tip: Combine Indicators with the Order Book
Define: trend filter, trigger signal, and confirmation. Example: EMA trend + RSI dip + rising bids.
Define: profit target, stop, and invalidation. Example: sell at VWAP touch or stop below last swing.
Use fixed size, percent of equity, or risk?based sizing. Keep consistency and avoid oversized positions.
Only take trades when all conditions align. If a condition fails, skip the entry. Discipline protects the account more than any single indicator.
Every variable explained in plain English, with practical notes for beginners.
Quick language tips (applies to all sections below): use if (...) { ... } to run rules, compare numbers with >, <, >=, <=, ===, and combine rules with && (AND) / || (OR). Wrap multiple actions with braces { ... } and place one action per line for clarity. Most variables are numbers; many flags use 1 = true and 0 = false. Percent values are literal (30 means 30%). Use // for comments, and use mem to remember state across candles (for example, track if you already bought).
Looking for full, complex scripts? Visit Auto Code Examples for complete auto?trading strategies and Indicator Examples for advanced indicator formulas.
These values tell you where you are in the data and help you control timing. They are great for delaying trades until enough candles exist.
tA normalized progress value from 0 to 1 for the current bar within the session. Think of it as a simple progress bar.
Example: Use t to fade colors over time or delay a rule until t > 0.5.
if (t > 0.5) {
// later in the session
hold();
}iThe index of the current candle in the series (0 is the first candle). In simple terms, this is the candle counter.
Example: Only trade after 50 bars with if (i > 50).
if (i > 50) {
// enough candles to trade
buyMarket(1);
}timeThe timestamp bucket of the current candle. Use it to detect when a new candle starts.
Example: Store time in mem to detect a new candle.
if (!mem.lastTime) mem.lastTime = time;
if (time != mem.lastTime) {
mem.lastTime = time;
hold();
}These are the core price and volume values for the current candle. Most indicators and strategies are built from these fields.
openThe price where the candle starts. This is the candle's starting price.
Example: Compare close to open to find green candles.
if (close > open) {
// green candle
hold();
}highThe highest traded price during the candle. This is the top price reached in that bar.
Example: Use high to set a stop above the candle.
const breakout = close > high;
if (breakout) {
buyMarket(1);
}lowThe lowest traded price during the candle. This is the bottom price reached in that bar.
Example: Use low to detect sell pressure or wick tests.
const breakdown = close < low;
if (breakdown) {
sellMarket(1);
}closeThe last price in the candle (final price once it closes). Most indicators are built from close.
Example: Check close > ema20 for trend filters.
if (close > ema20) {
buyMarket(1);
}volTotal traded volume in the candle. Higher volume means more participation.
Example: Require vol > volSma20 for confirmation.
if (vol > volSma20) {
buyMarket(1);
}prevOpenOpen price of the previous candle. Same idea as open, but one bar ago.
Example: Compare open to prevOpen to see opening drift.
if (open > prevOpen) {
// higher open
hold();
}prevHighHigh price of the previous candle. Same idea as high, but one bar ago.
Example: Use close > prevHigh for breakouts.
if (close > prevHigh) {
buyMarket(1);
}prevLowLow price of the previous candle. Same idea as low, but one bar ago.
Example: Use close < prevLow for breakdowns.
if (close < prevLow) {
sellMarket(1);
}prevCloseClose price of the previous candle. Same idea as close, but one bar ago.
Example: Use close - prevClose for momentum.
if (close > prevClose) {
hold();
}prevVolVolume of the previous candle. Same idea as vol, but one bar ago.
Example: Detect a volume spike with vol > prevVol * 1.5.
if (vol > prevVol * 1.5) {
buyMarket(1);
}prev2OpenOpen price two candles ago. Same idea as open, but two bars back.
Example: Compare open to prev2Open for short-term trend.
if (open > prev2Open) {
hold();
}prev2HighHigh price two candles ago. Same idea as high, but two bars back.
Example: Break above prev2High to confirm momentum.
if (close > prev2High) {
buyMarket(1);
}prev2LowLow price two candles ago. Same idea as low, but two bars back.
Example: Use close < prev2Low as a weakness signal.
if (close < prev2Low) {
sellMarket(1);
}prev2CloseClose price two candles ago. Same idea as close, but two bars back.
Example: Use close > prev2Close to confirm upward drift.
if (close > prev2Close) {
hold();
}prev2VolVolume two candles ago. Same idea as vol, but two bars back.
Example: Compare vol to prev2Vol to spot rising volume.
if (vol > prev2Vol) {
hold();
}Derived candle features explain the candle's shape. Use them to detect strong closes, rejections, and indecision.
rangeHigh minus low of the candle, showing raw volatility. Bigger range means a bigger move in that candle.
Example: Use range to avoid trading tiny candles.
if (range > atr14) {
// large candle
hold();
}rangePctRange expressed as a percent of close. This makes small and large prices comparable.
Example: Require rangePct > 0.5 for breakouts.
if (rangePct > 0.5) {
buyMarket(1);
}bodyThe absolute size of the candle body. It is the distance between open and close.
Example: A large body with low wicks can show conviction.
if (body > 0) {
hold();
}bodyPctBody size as a percent of open. This makes body size comparable across prices.
Example: Filter for strong moves with bodyPct > 0.3.
if (bodyPct > 0.3) {
buyMarket(1);
}bodyDirDirection: 1 bullish, -1 bearish. It is a quick up/down flag.
Example: Combine bodyDir with vol for trend bars.
if (bodyDir > 0) {
hold();
}isBull1 if close is above open. Think of it as a green candle flag.
Example: Count consecutive bulls: isBull this bar and previous.
if (isBull === 1) {
hold();
}isBear1 if close is below open. Think of it as a red candle flag.
Example: Use isBear for short filters.
if (isBear === 1) {
hold();
}isDoji1 if body is very small relative to price. Doji often signals indecision.
Example: Avoid entries on isDoji === 1.
if (isDoji === 1) {
hold();
}gapOpen minus previous close (positive is gap up). It shows a jump between candles.
Example: Use gap > 0 to detect gap-and-go.
if (gap > 0) {
buyMarket(1);
}gapPctGap expressed as a percent of previous close. This makes gaps comparable across prices.
Example: Require gapPct > 0.2 for strong gap setups.
if (gapPct > 0.2) {
buyMarket(1);
}gapDirGap direction: 1 up, -1 down, 0 flat. This is the gap as a simple flag.
Example: Only trade gaps when gapDir === 1.
if (gapDir === 1) {
hold();
}upperWickSize of the upper wick. Big upper wicks can mean price was rejected.
Example: Large upperWick can signal rejection.
if (upperWick > lowerWick) {
hold();
}lowerWickSize of the lower wick. Big lower wicks can mean buying support.
Example: Large lowerWick can signal buying pressure.
if (lowerWick > upperWick) {
hold();
}upperWickPctUpper wick as a percent of range. Percent makes wick size comparable.
Example: Use upperWickPct > 60 to detect rejection.
if (upperWickPct > 60) {
hold();
}lowerWickPctLower wick as a percent of range. Percent makes wick size comparable.
Example: Use lowerWickPct > 60 for wick-buy signals.
if (lowerWickPct > 60) {
hold();
}hlRangePctHigh-low range as a percent of close. Good for comparing volatility across prices.
Example: Use hlRangePct to scale stop distance.
if (hlRangePct > 0.6) {
hold();
}closePosClose position in the range (0 bottom to 1 top). Values near 1 mean strong closes.
Example: Use closePos > 0.8 to find strong closes.
if (closePos > 0.8) {
buyMarket(1);
}hl2Midpoint of high and low (H+L)/2. A simple center price for the candle.
Example: Use hl2 as a simple mean price filter.
if (close > hl2) {
hold();
}hlc3Average of high, low, close (H+L+C)/3. A common "typical" price.
Example: Compare close vs hlc3 for bias.
if (close > hlc3) {
hold();
}ohlc4Average of open, high, low, close (O+H+L+C)/4. It smooths the candle even more.
Example: Use ohlc4 in custom smoothing formulas.
if (close > ohlc4) {
hold();
}typicalTypical price, same as HLC3. Use it as a simple average price.
Example: Use typical for VWAP-style logic.
if (close > typical) {
hold();
}Return and range values help you measure speed and volatility. They are useful for sizing trades and setting targets.
changeClose minus previous close, the raw price change. Positive means price rose.
Example: change > 0 means the bar closed higher.
if (change > 0) {
hold();
}changePctPercent change versus the previous close. This makes changes comparable across prices.
Example: Use changePct > 0.2 for strong momentum bars.
if (changePct > 0.2) {
buyMarket(1);
}logReturnLog return between closes for smoother stats. It reduces the impact of big jumps.
Example: Average logReturn to estimate drift.
if (logReturn > 0) {
hold();
}trueRangeTrue range that includes gaps between candles. It reflects real movement better than raw range.
Example: Use trueRange to set stops in volatile markets.
if (trueRange > atr14) {
hold();
}atr7ATR over 7 bars, fast volatility. Higher values mean recent candles are larger.
Example: Use atr7 for tight scalping stops.
if (atr7 > atr14) {
hold();
}atr14ATR over 14 bars, standard volatility. Think of it as a typical candle size.
Example: Use atr14 to size positions by risk.
if (atr14 > 0) {
hold();
}atr21ATR over 21 bars, slower volatility. This changes more slowly than atr14.
Example: Use atr21 for swing-style targets.
if (atr21 > atr14) {
hold();
}atrPctATR as a percent of current price. This helps compare volatility across instruments.
Example: Use atrPct to normalize stops across price levels.
if (atrPct > 1) {
hold();
}Moving averages smooth price. You can use them as trend filters, dynamic support/resistance, or crossover signals.
sma5SMA of last 5 closes for short trend. Shorter SMAs react faster to price changes.
Example: If close > sma5, short-term bias is up.
if (close > sma5) {
buyMarket(1);
}sma10SMA of last 10 closes for micro trend. It moves faster than longer averages.
Example: Use sma10 as a trailing support level.
if (close > sma10) {
hold();
}sma20SMA of last 20 closes for common trend filter. Many traders use this as a basic trend line.
Example: Trade long only when close > sma20.
if (close > sma20) {
buyMarket(1);
}sma50SMA of last 50 closes for mid trend. It is smoother and slower than sma20.
Example: Use sma50 to avoid counter-trend entries.
if (close > sma50) {
hold();
}sma100SMA of last 100 closes for major trend. This is a very slow, long-term average.
Example: Only trade with direction of sma100.
if (close > sma100) {
hold();
}ema5EMA of last 5 closes, very reactive. EMA responds faster than SMA.
Example: Use ema5 for fast crossover entries.
if (close > ema5) {
buyMarket(1);
}ema10EMA of last 10 closes, fast trend. It reacts quickly to new prices.
Example: Use ema10 to trail stops.
if (close > ema10) {
hold();
}ema20EMA of last 20 closes, common trend line. Many strategies use it as a baseline.
Example: Trade only when price is above ema20.
if (close > ema20) {
buyMarket(1);
}ema50EMA of last 50 closes, mid trend. Smoother and slower than ema20.
Example: Use ema50 for swing confirmation.
if (close > ema50) {
hold();
}ema100EMA of last 100 closes, long trend. It changes very slowly.
Example: Avoid longs if close is below ema100.
if (close > ema100) {
hold();
}smaDiffSMA10 minus SMA20, trend spread. Positive means short-term is above mid-term.
Example: smaDiff > 0 suggests bullish pressure.
if (smaDiff > 0) {
hold();
}emaDiffEMA10 minus EMA20, trend spread. Positive means short-term momentum is higher.
Example: emaDiff turning positive signals trend shift.
if (emaDiff > 0) {
hold();
}ema10SlopeChange of EMA10 from previous bar. Positive means EMA10 is rising.
Example: Require ema10Slope > 0 to enter longs.
if (ema10Slope > 0) {
hold();
}sma20SlopeChange of SMA20 from previous bar. Positive means the trend line is rising.
Example: If sma20Slope < 0, avoid longs.
if (sma20Slope > 0) {
hold();
}priceAboveSma201 if close is above SMA20. A simple yes/no trend filter.
Example: Use priceAboveSma20 === 1 as a filter.
if (priceAboveSma20 === 1) {
hold();
}priceAboveEma201 if close is above EMA20. Another quick yes/no trend check.
Example: Require priceAboveEma20 for trend trades.
if (priceAboveEma20 === 1) {
hold();
}trendUp1 when EMA10 is at or above EMA20, else -1. Think of it as a simple trend direction flag.
Example: trendUp > 0 can enable only long trades.
if (trendUp > 0) {
hold();
}Momentum indicators show how fast price is moving. Use them to avoid chasing exhausted moves.
rsi7RSI over 7 periods for fast momentum. Low values suggest oversold, high values suggest overbought.
Example: Buy dips when rsi7 < 20 and trendUp is positive.
if (rsi7 < 30) {
buyMarket(1);
}rsi14Standard 14-period RSI. The most common RSI length used by traders.
Example: Consider selling when rsi14 > 70.
if (rsi14 > 70) {
sellMarket(1);
}rsi21Slow 21-period RSI for smoother trend. It changes more slowly than rsi14.
Example: Use rsi21 > 50 as a trend filter.
if (rsi21 > 50) {
hold();
}rsiSlopeChange in RSI14 from previous bar. Positive means RSI is rising.
Example: rsiSlope > 0 can confirm rising momentum.
if (rsiSlope > 0) {
hold();
}roc12Rate of change over 12 bars. Positive means price is higher than 12 bars ago.
Example: roc12 > 0 indicates upward acceleration.
if (roc12 > 0) {
hold();
}stochKStochastic %K (0-100), position inside recent range. Near 0 is near the low, near 100 is near the high.
Example: Look for stochK < 20 for oversold bounces.
if (stochK < 20) {
buyMarket(1);
}stochDSmoothed Stochastic signal line. It helps reduce noise in %K.
Example: Use stochK crossing above stochD as a trigger.
if (stochK > stochD) {
hold();
}macdLineMACD line, EMA12 minus EMA26. Positive means short-term is above long-term.
Example: macdLine > 0 suggests bullish momentum.
if (macdLine > 0) {
buyMarket(1);
}macdSignalMACD signal line, EMA9 of MACD line. Use it as a smoother comparison line.
Example: Buy when macdLine crosses above macdSignal.
if (macdLine > macdSignal) {
hold();
}macdHistMACD histogram, MACD line minus signal line. Bigger values mean stronger momentum.
Example: Rising macdHist can confirm acceleration.
if (macdHist > 0) {
hold();
}Volume confirms participation. Bands show volatility expansion or contraction and are useful for mean?reversion setups.
vwapVolume weighted average price across the session. Think of it as the session's fair price.
Example: Consider longs when close > vwap.
if (close > vwap) {
buyMarket(1);
}obvOn-Balance Volume, cumulative flow based on price direction. Rising OBV can mean buyers are stronger.
Example: Rising obv with flat price can hint accumulation.
if (obv > 0) {
hold();
}closeAboveVwap1 if close is above VWAP, else 0. A simple yes/no filter for VWAP direction.
Example: Combine with trendUp for higher-quality setups.
if (closeAboveVwap === 1) {
hold();
}volSma5Average volume over 5 bars. Use it as a short-term volume baseline.
Example: Use vol > volSma5 to detect strong participation.
if (vol > volSma5) {
hold();
}volSma20Average volume over 20 bars. A common mid-term volume baseline.
Example: Use volRel based on volSma20 for filters.
if (vol > volSma20) {
hold();
}volSma50Average volume over 50 bars. A slower baseline for longer-term activity.
Example: Use volSma50 for long-term volume baseline.
if (vol > volSma50) {
hold();
}volChangeCurrent volume minus previous volume. Positive means activity is rising.
Example: volChange > 0 indicates growing participation.
if (volChange > 0) {
hold();
}volChangePctPercent change of volume versus previous bar. Helps compare volume spikes across bars.
Example: Use volChangePct > 30 for volume spikes.
if (volChangePct > 30) {
hold();
}volRelVolume relative to volSma20 (1.0 is average). Values above 1 mean above-average volume.
Example: Require volRel > 1.2 for breakout confirmation.
if (volRel > 1.2) {
hold();
}bbUpperUpper Bollinger Band (volatility ceiling). Price near this line is relatively high.
Example: If close > bbUpper, volatility expansion may be underway.
if (close > bbUpper) {
sellMarket(1);
}bbMiddleMiddle Bollinger Band (the SMA line). It is the center line of the bands.
Example: Use bbMiddle as mean reversion target.
if (close > bbMiddle) {
hold();
}bbLowerLower Bollinger Band (volatility floor). Price near this line is relatively low.
Example: If close < bbLower, price is extended down.
if (close < bbLower) {
buyMarket(1);
}bbWidthBand width, upper minus lower. Bigger width means higher volatility.
Example: Low bbWidth can signal a squeeze.
if (bbWidth < 0.5) {
hold();
}bbPctBPercent-B position inside the bands (0 to 1). 0 is near the lower band, 1 is near the upper.
Example: bbPctB < 0.1 means price is near the lower band.
if (bbPctB < 0.1) {
buyMarket(1);
}Helpers let you compute indicators directly on arrays. This is useful when you want custom logic beyond built?ins.
dataArray of candle objects for the entire session. Use it to access full history.
Example: Access raw history with data[i - 5].
if (data.length > 10) {
const last = data[data.length - 1];
hold();
}opensArray of open prices aligned by index. Each item matches the same candle index.
Example: Use opens[i] to compare with current close.
if (opens.length > i) {
const o = opens[i];
hold();
}highsArray of high prices aligned by index. Think of it as the "high" history list.
Example: Use highest(highs, 20, i) for breakout levels.
if (highs.length > i) {
const h = highs[i];
hold();
}lowsArray of low prices aligned by index. Think of it as the "low" history list.
Example: Use lowest(lows, 20, i) for support levels.
if (lows.length > i) {
const l = lows[i];
hold();
}closesArray of close prices aligned by index. Most custom calculations use closes.
Example: Use ema(closes, 10, i) inside custom logic.
if (closes.length > i) {
const c = closes[i];
hold();
}volsArray of volume values aligned by index. Use it to compute volume averages.
Example: Use sma(vols, 20, i) for volume average.
if (vols.length > i) {
const v = vols[i];
hold();
}sma(arr,p,i)Helper: SMA of arr with period p at index i. Returns null until enough data exists.
Example: sma(closes, 20, i) to compute SMA20 inline.
const sma20 = sma(closes, 20, i);
if (sma20 !== null && close > sma20) {
buyMarket(1);
}ema(arr,p,i)Helper: EMA of arr with period p at index i. It reacts faster than SMA.
Example: ema(closes, 10, i) for custom EMA.
const ema10 = ema(closes, 10, i);
if (ema10 !== null && close > ema10) {
hold();
}highest(arr,p,i)Helper: highest value in the last p points. Useful for breakout levels.
Example: highest(highs, 20, i) for breakouts.
const recentHigh = highest(highs, 20, i);
if (recentHigh !== null && close > recentHigh) {
buyMarket(1);
}lowest(arr,p,i)Helper: lowest value in the last p points. Useful for support levels.
Example: lowest(lows, 20, i) for supports.
const recentLow = lowest(lows, 20, i);
if (recentLow !== null && close < recentLow) {
sellMarket(1);
}sum(arr,p,i)Helper: sum of the last p values. Use it to build custom averages.
Example: sum(vols, 5, i) for recent volume.
const volSum = sum(vols, 5, i);
if (volSum !== null) {
hold();
}avg(arr,p,i)Helper: average of the last p values. A quick mean without writing a loop.
Example: avg(closes, 5, i) for quick mean.
const closeAvg = avg(closes, 5, i);
if (closeAvg !== null && close > closeAvg) {
hold();
}std(arr,p,i)Helper: standard deviation over last p values. Higher values mean more spread.
Example: std(closes, 20, i) for volatility.
const volStd = std(closes, 20, i);
if (volStd !== null) {
hold();
}These describe your portfolio and last trade. Use them to control risk, position size, and trade frequency.
balanceCash available for new buys. If this is too low, buys will fail.
Example: Check balance > price * 5 before buying.
if (balance > price * 5) {
buyMarket(5);
}holdingsNumber of shares currently held. If 0, you have no position.
Example: Use holdings > 0 to allow sells.
if (holdings > 0) {
hold();
}avgPriceAverage entry price of your position. Use it to know if you are in profit.
Example: Compute unrealized PnL with (price - avgPrice) * holdings.
if (holdings > 0 && price > avgPrice) {
hold();
}priceAlias of the current price (same as close). Use this in order calculations.
Example: Use price to compute limit prices.
if (price > ema20) {
buyMarket(1);
}equityTotal account value: cash plus position value. This is your true account size.
Example: Use equity for percent-based sizing.
if (equity > 1000) {
hold();
}pnlUnrealized profit or loss of the current position. Positive means you are up.
Example: If pnl > 50, scale out.
if (pnl > 50) {
sellPct(50);
}returnRateReturn percentage versus the starting balance. A quick snapshot of overall performance.
Example: Pause trading if returnRate < -5.
if (returnRate < -5) {
hold();
}positionValueCurrent position value (holdings * price). This is how much your position is worth now.
Example: Use sellPct(50) to sell half of this value.
if (positionValue > 0) {
hold();
}lastTradeObject with last trade info: type, price, qty, time, kind. Use it to avoid repeating actions.
Example: Use lastTrade.type === 'BUY' to avoid double entries.
if (lastTrade && lastTrade.type === 'BUY') {
hold();
}Choose the order type based on how urgent the entry/exit is. Market is instant; limit/stop are conditional.
MarketExecutes immediately at the current price. Best when speed matters more than price.
Example: Use market orders for instant entries in fast moves.
buyMarket(1);
// immediate execution at current priceLimitReserved order that fills only when price crosses the limit. Good for better prices.
Example: Place a limit buy below price to catch pullbacks.
buyLimit(price * 0.995, 2);
// waits until price drops to limitStopTriggers when price crosses a stop level, then executes at market. Often used as a safety exit.
Example: Use a stop sell below price for protection.
sellStop(price * 0.99, 2);
// triggers on stop levelStop-LimitTriggers on a stop, then becomes a limit order. Gives price control after the trigger.
Example: Use stop-limit to control slippage on breakouts.
buyStop(price * 1.01, 2, price * 1.015);
// stop triggers then becomes limitWhen a limit or stop order fills, you will see a trade log tag like (LIMIT)/(STOP) and a toast message.
Each helper below includes a complete code line you can paste as?is into auto?trading logic.
orderQtyCurrent quantity from the Order Qty input on the trading screen. This mirrors the UI number.
Example: Use the UI quantity directly.
if (orderQty > 0) { buyOrderQty(); }setOrderQty(qty)Updates the Order Qty input from code and returns the normalized value. Useful before a buy/sell.
Example: Set UI order size before buying.
setOrderQty(10);
buyOrderQty();buyOrderQty()Market buy using the current Order Qty input. It buys exactly what the UI shows.
Example: Buy the UI size on a signal.
if (rsi14 < 30) { buyOrderQty(); }sellOrderQty()Market sell using the current Order Qty input. It sells exactly what the UI shows.
Example: Sell the UI size on a signal.
if (holdings > 0 && rsi14 > 70) { sellOrderQty(); }buy(qty)Market buy for a fixed quantity. qty is the number of shares.
Example: Buy 3 shares once per bar.
if (oncePerBar('mktBuy')) { buy(3); }sell(qty)Market sell for a fixed quantity. qty is the number of shares.
Example: Sell 2 shares if RSI is high.
if (holdings > 0 && rsi14 > 70) { sell(2); }hold()No action; useful for clarity in conditions. Think of it as "do nothing."
Example: Use to explicitly do nothing in a branch.
if (trendUp < 0) { hold(); }buyMarket(qty)Explicit market buy using the current price. Same as buy(qty) but clearer.
Example: Enter when momentum turns positive.
if (macdHist > 0) { buyMarket(5); }sellMarket(qty)Explicit market sell using the current price. Same as sell(qty) but clearer.
Example: Exit when momentum flips negative.
if (holdings > 0 && macdHist < 0) { sellMarket(5); }buyLimit(price, qty)Limit buy at or below a target price. The order waits until price hits the limit.
Example: Bid slightly below current price.
if (oncePerBar('bid')) { buyLimit(price * 0.995, 4); }sellLimit(price, qty)Limit sell at or above a target price. The order waits until price hits the limit.
Example: Take profit a bit above price.
if (holdings > 0) { sellLimit(price * 1.01, 4); }buyStop(stop, qty, limitPrice?)Stop buy that triggers on breakout (optional stop-limit). It activates only after price crosses the stop.
Example: Buy if price breaks higher.
if (trendUp > 0) { buyStop(price * 1.01, 3); }sellStop(stop, qty, limitPrice?)Stop sell for protection (optional stop-limit). It activates only after price crosses the stop.
Example: Protect position below price.
if (holdings > 0) { sellStop(price * 0.99, 3); }buyPct(pct)Market buy using a percent of equity. Equity means cash plus position value.
Example: Use 25 percent of equity on dips.
if (rsi14 < 30) { buyPct(25); }sellPct(pct)Market sell using a percent of position value. 50 means sell half.
Example: Sell half when RSI is high.
if (holdings > 0 && rsi14 > 70) { sellPct(50); }buyValue(amount)Market buy using a fixed cash amount. Good for dollar-based sizing.
Example: Buy 250 dollars every 5 seconds.
if (cooldown('val', 5000)) { buyValue(250); }sellValue(amount)Market sell a fixed value of holdings. You sell by dollars, not shares.
Example: Sell 200 dollars of position.
if (holdings > 0) { sellValue(200); }riskQty(opts)Position sizing by risk percent and stop distance. Helps keep losses consistent.
Example: Risk 1 percent with a 1 percent stop.
const qty = riskQty({ riskPct: 1, stopPct: 1 }); if (qty > 0) buy(qty);cooldown(key, ms)Rate-limit actions using a key and milliseconds. Prevents repeated orders too fast.
Example: Avoid spamming entries on every tick.
if (cooldown('entry', 3000)) { buy(1); }oncePerBar(key)Runs logic only once per candle. Useful to avoid duplicate orders in the same bar.
Example: Prevent duplicate orders in a single bar.
if (oncePerBar('scale')) { sell(1); }memPersistent memory object for strategy state. Store flags so logic remembers past actions.
Example: Save mode across ticks in mem.mode.
if (!mem.mode) mem.mode = 'trend';ctxContext object with timing and bar metadata. Read-only info about the current tick.
Example: Use ctx.tick to run periodic actions.
if (ctx.tick % 20 === 0) { mem.lastPulse = ctx.now; }10+ complete strategies using advanced variables and order helpers.
Each block below is runnable as-is inside the Auto Trading Code box. Every example uses multiple variables and helpers to show real strategy complexity.
Buys in an uptrend when price is above VWAP and RSI is oversold, sizes by risk, scales out on strength, and exits if trend breaks.
// Trend + VWAP + RSI + Risk Sizing
if (oncePerBar('setup')) {
if (trendUp > 0 && closeAboveVwap === 1 && rsi14 < 40 && volRel > 1.1) {
const qty = riskQty({ riskPct: 1, stopPct: 1.2, price });
if (qty > 0 && balance > price * qty) buyMarket(qty);
}
}
if (holdings > 0 && (rsi14 > 70 || macdHist < 0)) {
sellPct(50);
}
if (holdings > 0 && price < ema20) {
sellMarket(holdings);
}
Places stop buys above recent highs, protects with stop sells, and throttles order placement with a cooldown.
// Breakout + Stop Orders + Cooldown
const recentHigh = highest(highs, 20, i);
const recentLow = lowest(lows, 20, i);
if (cooldown('brk', 3000) && recentHigh !== null && trendUp > 0 && bbWidth > 0.2) {
buyStop(recentHigh * 1.002, 3);
}
if (holdings > 0 && recentLow !== null) {
sellStop(recentLow * 0.998, Math.min(holdings, 3));
}
if (holdings > 0 && macdLine < macdSignal && rsiSlope < 0) {
sellPct(25);
}
Buys near the lower band with oversold momentum and sells near the upper band or when momentum fades.
// Mean Reversion + Bollinger Bands + Stoch
if (oncePerBar('mr') && bbLower !== null && bbUpper !== null) {
if (close < bbLower && stochK < 20 && rsi7 < 30 && volRel > 1.0) {
buyValue(300);
}
}
if (holdings > 0 && (close > bbUpper || stochK > 80 || rsi14 > 70)) {
sellValue(300);
}
if (holdings > 0 && closePos < 0.2 && lowerWickPct > 50) {
sellPct(25);
}
Enters when EMA slope, EMA spread, and MACD histogram align with strong volume. Exits if momentum or volume fades.
// Momentum Stack + EMA Slopes + Volume Filter
if (oncePerBar('mom') && ema10Slope > 0 && emaDiff > 0 && macdHist > 0 && volRel > 1.2) {
buy(4);
}
if (holdings > 0 && (ema10Slope < 0 || macdHist < 0 || volRel < 0.8)) {
sellPct(50);
}
if (holdings > 0 && close < sma20 && bodyDir < 0) {
sellMarket(holdings);
}
Arms a breakout when Bollinger width is tight, then uses stop orders to catch expansion and manages risk with stop-loss.
// Volatility Squeeze + Expansion
if (!mem.squeeze) mem.squeeze = false;
if (bbWidth < 0.15 && atrPct < 1) mem.squeeze = true;
if (mem.squeeze && cooldown('sq', 2000)) {
const hi = highest(highs, 15, i);
const lo = lowest(lows, 15, i);
if (hi !== null && lo !== null) {
buyStop(hi * 1.003, 2);
sellStop(lo * 0.997, 2);
}
}
if (holdings > 0 && (bbWidth > 0.3 || rsi14 > 70)) {
sellPct(50);
}
Trades gaps using gap direction and size; continues gaps with VWAP confirmation or fades extreme gaps when momentum stalls.
// Gap & Go / Gap Fade Hybrid
if (oncePerBar('gap')) {
if (gapDir === 1 && gapPct > 0.2 && closeAboveVwap === 1 && rsi14 > 50) {
buyMarket(3);
}
if (gapDir === -1 && gapPct > 0.2 && closeAboveVwap === 0 && rsi14 < 50) {
sellMarket(3);
}
}
if (holdings > 0 && rsiSlope < 0 && upperWickPct > 60) {
sellPct(50);
}
Buys pullbacks in an uptrend when price holds above EMA20 and shows lower-wick support, then exits on weakness.
// Trend Pullback with Wicks
if (trendUp > 0 && priceAboveEma20 === 1 && oncePerBar('pb')) {
if (closePos < 0.3 && lowerWickPct > 50 && volRel > 0.9) {
const qty = riskQty({ riskPct: 0.8, stopPct: 1.0 });
if (qty > 0) buyLimit(price * 0.995, qty);
}
}
if (holdings > 0 && (ema10Slope < 0 || close < sma20)) {
sellMarket(holdings);
}
Trades inside ranges using close position and stochastic signals, scaling in/out with percent-based orders.
// Range Scalper
if (oncePerBar('range') && hlRangePct < 0.8 && atrPct < 1.2) {
if (closePos < 0.2 && stochK < 20) buyPct(10);
if (closePos > 0.8 && stochK > 80) sellPct(25);
}
if (holdings > 0 && rsi14 > 70) sellPct(25);
Detects climax volume and wick rejection to reverse into mean reversion, then takes partial profits on recovery.
// Volume Climax Reversal
if (oncePerBar('climax')) {
if (volChangePct > 80 && upperWickPct > 60 && rsi14 > 70) {
sellMarket(3);
}
if (volChangePct > 80 && lowerWickPct > 60 && rsi14 < 30) {
buyMarket(3);
}
}
if (holdings > 0 && closePos > 0.7) sellPct(30);
Uses mem to switch between trend and risk-off modes, and avoids repeated entries within the same state.
// Regime Switching with Memory
if (!mem.mode) mem.mode = 'wait';
if (trendUp > 0 && priceAboveSma20 === 1) mem.mode = 'trend';
if (trendUp < 0 && priceAboveSma20 === 0) mem.mode = 'riskoff';
if (mem.mode === 'trend' && oncePerBar('entry') && rsi14 < 45 && closeAboveVwap === 1) {
const qty = riskQty({ riskPct: 1, stopPct: 1.0 });
if (qty > 0) buy(qty);
}
if (mem.mode === 'riskoff' && holdings > 0) {
sellPct(50);
}
Stops trading after a drawdown, reduces exposure when returns fall, and uses PnL to take profit.
// Drawdown Guard + Equity Control
if (returnRate < -5) {
if (holdings > 0) sellMarket(holdings);
hold();
}
if (returnRate < -2 && holdings > 0) {
sellPct(25);
}
if (pnl > 80) {
sellPct(30);
}
Computes a size based on volatility, updates the UI order size, and uses UI-based buy/sell helpers.
// Adaptive Size + UI Quantity
if (oncePerBar('size')) {
const riskSize = riskQty({ riskPct: 0.8, stopPct: Math.max(0.5, atrPct) });
if (riskSize > 0) setOrderQty(riskSize);
}
if (trendUp > 0 && rsi14 < 40 && closeAboveVwap === 1) {
buyOrderQty();
}
if (holdings > 0 && (rsi14 > 70 || macdHist < 0)) {
sellOrderQty();
}
10+ advanced indicator formulas you can paste into the Custom Indicator box.
Each example returns a price-scaled value (so it overlays cleanly on the price chart). You can paste one formula at a time.
Tracks a blend of price and VWAP to smooth pullbacks while staying near the price scale.
// VWAP Pullback Line
return (vwap * 0.7) + (close * 0.3);
A weighted blend of EMA10 and EMA20 to create a responsive trend line.
// EMA Trend Blend
return (ema10 * 0.6) + (ema20 * 0.4);
Shifts price by volatility to highlight expansion moves.
// ATR-Weighted Price
return close + (atr14 * 0.5 * bodyDir);
Adds momentum (MACD histogram) to SMA20 for faster response.
// Momentum-Adjusted SMA
return sma20 + (macdHist * 0.8);
Tilts the midline higher when RSI is bullish and lower when RSI is weak.
// RSI-Bias Midline
const bias = (rsi14 - 50) / 100;
return close + (atr14 * bias);
Boosts the close when volume is above average, dampens when below.
// Volume-Weighted Close
const vBoost = Math.max(0.5, Math.min(1.5, volRel));
return close * vBoost;
Projects where price sits within Bollinger Bands and maps it back to price scale.
// Bollinger Percent-B Price
if (bbUpper === null || bbLower === null) return close;
return bbLower + (bbWidth * bbPctB);
Combines EMA spread and slope to show trend strength as a price overlay.
// Trend Strength Line
const strength = (emaDiff * 2) + (ema10Slope * 5);
return close + strength;
Anchors to HLC3 and pulls toward it when price is stretched.
// Mean Reversion Anchor
const stretch = (close - hlc3);
return close - (stretch * 0.6);
Moves the line toward the wick that shows stronger rejection.
// Wick Rejection Line
const wickBias = (upperWickPct - lowerWickPct) / 100;
return close - (atr14 * wickBias);
Uses Stochastic to bias price higher or lower based on momentum position.
// Stochastic-Weighted Price
const kBias = (stochK - 50) / 50;
return close + (atr14 * 0.3 * kBias);
Adds OBV slope to price to highlight volume-driven drift.
// OBV Drift Overlay
const drift = Math.tanh((obv / Math.max(1, volSma20)) * 0.01);
return close + (atr14 * drift);