Skip to main content

Building a Futures Strategy by Hand

In this tutorial we're going to do what the Trading Mindset page said traders should do: observe a pattern, form a testable rule, and actually test it. No hand-waving. No "this setup has a 90% win rate" nonsense. Just a concrete strategy we'll build from scratch, backtest with real historical data, and then iterate on — honestly.

What you'll learn
  • How to turn a chart observation into a specific, testable strategy
  • How to build a strategy by hand using the visual block editor
  • How the is_first_run block handles one-time initialization cleanly
  • How to express streak-and-reversal logic with a stateful flag
  • How to wire a futures order with leverage, collateral, stop loss, and take profit
  • How to read a backtest report — what the numbers actually mean
  • How to iterate on a strategy when the first version isn't profitable
  • The difference between an in-sample tweak and an out-of-sample test — and why both matter

Why build by hand?

BrighterTrading has a Generate with AI button in the strategy dialog that will build a strategy from a plain-English description. It's a real time-saver once you know what you're doing. But this tutorial deliberately avoids it, because:

  1. Understanding comes from doing. If you can't build a strategy by hand, you can't debug one the AI built.
  2. You learn what blocks exist. The toolbox has more than a dozen categories. You won't discover half of them unless you go looking.
  3. You learn the patterns. Every strategy you write will repeat certain shapes — initialization blocks, entry conditions, risk management, state tracking. Doing it once by hand burns them into muscle memory.

Once you've done this tutorial, the AI generator becomes a useful collaborator rather than a black box.

The observation

We're on BTC/USDT, Binance, 12h timeframe. Here's what we're looking at:

BTC/USDT 12h chart showing streak behaviour

The 12h BTC/USDT chart shows a recurring pattern: clusters of green candles followed by clusters of red ones. This "streak and reversal" behaviour is what we want to exploit.

Take a moment to look at it. Notice the clusters. Notice that after a run of green candles, the first red candle is often followed by more red candles — not just one. And after a run of reds, green tends to come back.

This is autocorrelation in action

Markets often show short-term momentum. Streaks of the same-coloured candles happen more often than pure randomness would predict. Whether exploiting that momentum is profitable after fees is a different question — which is exactly why we backtest.

The hypothesis

Our observation gives us a concrete, testable rule:

After at least 2 green candles in a row, when the next candle closes red, short at the close of that red candle. Place a stop loss above the red candle's high and a take profit below the entry by some multiple of the candle's volatility.

In plain English:

EntryShort at the close of the first red candle following 2+ greens
Stop lossAbove the red candle's high, sized by volatility
Take profitBelow the entry, sized by volatility, larger than the stop
Leverage10×
Collateral5% of available balance

We'll start with the candle's own range as our volatility measure, then later swap in ATR (average true range) — a smoother, multi-candle volatility estimate.

Two ways to interpret a streak

A red candle after a green streak can be read two ways:

  • Mean reversion — "the trend is exhausting, short it." (This is our hypothesis.)
  • Trend continuation — "that red is just a pullback; the uptrend resumes, buy the dip."

Both interpretations exist in real markets. Which one is right for BTC 12h? We don't know yet. That's the whole reason we backtest.

Opening the strategy builder

Open the Strategies panel in the right sidebar, and click New Strategy.

New strategy dialog in default position

The strategy dialog as it opens. Name it something descriptive — we used "Streak Reversal Short BTC 12h". Notice the exchange, symbol, and timeframe are already pre-filled to match the chart you were looking at.

Before you start dragging blocks, set up your workspace:

  1. Move the dialog to the left side of the screen by clicking and dragging its header
  2. Resize it larger by dragging the bottom-right corner outward

Builder after being repositioned and expanded

A bigger canvas makes block assembly much less cramped. Do this every time.

Workspace tip

Most people skip the resize step. Don't. The default canvas is small, and once you've got six or seven blocks nested together, you'll be scrolling constantly. Expand first, build second.

Step 1: The initialization block

A well-written strategy has two phases:

  1. Initialization — runs once, on the very first tick. Sets up constants: trading mode, leverage, collateral sizing.
  2. Per-tick logic — runs every tick. Checks conditions, places trades, updates state.

BrighterTrading exposes a special boolean block called Is first run that returns true on the strategy's first tick and false after. Plug it into an execute_if and you have a clean one-time setup hook.

The pseudocode:

if is_first_run:
Set Mode Futures, Leverage 10x
collateral = available_balance × 0.05

Building the init block

  1. From Control, drag out an If ___ then (execute_if) block onto the canvas.
  2. From Control, drag the Is first run block and plug it into the If's condition slot.
  3. Inside the If's body, in this order:
    • From Trading, drag Set Mode ___ Leverage ___ x. Set the dropdown to Futures and the number to 10.
    • From Values and Flags, drag Set Variable ___ to ___. Rename the variable to collateral.
    • From Math, drag the arithmetic block (a × b) into the variable's value slot. Operator: ×.
    • From Balances, drag Available Balance into the left side of the multiplication.
    • From Values and Flags, drag a Value block into the right side of the multiplication, and edit it to 0.05.

When you're done, your init block should look like this:

Completed init block

The full initialization: wrapped in an If [Is first run] check, sets futures leverage to 10x, then sets collateral to 5% of available balance. Runs once, on the first tick. Skipped every tick after.

Why a percentage instead of a fixed dollar amount?

We use available_balance × 0.05 instead of a hardcoded $100 because percentages scale with the account size. A strategy that's profitable on $10k should also be profitable on $100k or $1M without any code changes. Risk management with fixed dollar amounts breaks down at the extremes.

Step 2: The streak detector

Now for the per-tick logic — the part that runs on every closed candle and decides whether to trade.

Our condition: the last 2 candles were green, and the current candle just closed red.

You might be tempted to write this directly:

if last 2 candles all Green AND current candle is Red:
short

But there's a contradiction. The "last 2 candles" check includes the current (most recently closed) candle. So last 2 candles all Green requires candle 0 to be green, but current candle is Red requires candle 0 to be red. Both can't be true at the same time, and the strategy would never fire.

There are two ways to resolve this:

  1. Look back further with explicit candle offsets — check candles 1 and 2 are green AND candle 0 is red.
  2. Use a flag — on each tick, remember whether the previous tick saw a 2-green streak. On the next tick, check the flag AND the new candle's colour.

We'll use the flag approach. It teaches a pattern you'll reuse: stateful logic that carries information across ticks.

The pseudocode:

# Each tick:
# 1. Check trade condition (uses flag set on the *previous* tick)
if green_streak flag is True AND current candle is Red AND no position open:
place the short

# 2. Reset the flag — we'll re-set it below if the streak is still alive
green_streak flag = False

# 3. If the last 2 candles are green right now, set the flag for next tick
if last 2 candles all Green:
green_streak flag = True

The trade check must come before the reset and re-set. If you do it the other way around, the flag reflects the current tick's streak — and you're back to the contradiction.

The reset-then-set idiom

Resetting the flag to False and then conditionally setting it to True keeps the flag accurately reflecting "is the streak alive right now". Without the reset, the flag would stay True forever once set. This is a useful general pattern for any flag that should track current state, not historical state.

Building the trade-check block (Stack 2)

Drag a fresh If ___ then (execute_if) onto the canvas, below your init block. The condition is a chain of three ANDs:

  1. Flag is set: From Values and Flags, drag Flag ___ is set ___. Name it green_streak, value True.
  2. Current candle is red: From Market Data, drag Candle [0] bars ago is [Red]. The 0 means the most recently closed candle.
  3. No position open: From Logical, drag is false. From Trading, drag has open position into its slot.

Wire all three into a logical_and chain. The body of this If is where the trade goes — we'll fill it in next.

Building the flag bookkeeping (Stack 3)

Below the trade block, place these in order:

  1. From Values and Flags, drag Set Flag ___ to ___. Name green_streak, value False. This is the unconditional reset.
  2. From Control, drag another If ___ then.
  3. From Market Data, drag Last [2] candles all [Green] into its condition slot.
  4. Inside the If's body, drag another Set Flag green_streak to True.

Now you have three top-level stacks: init, trade-check, flag-bookkeeping. The vertical order on the canvas determines execution order, so make sure they're laid out top-to-bottom in that exact sequence.

Stack order matters

When you have multiple disconnected top-level stacks, BrighterTrading executes them in top-to-bottom visual order. If you rearrange the stacks, you change the program. If you want execution order to be unambiguous, chain the blocks together — connect the bottom of one stack to the top of the next so they form a single continuous block. We'll do that at the end.

Step 3: The trade body

Inside the trade-check If (Stack 2), we need to:

  1. Compute the stop loss price
  2. Compute the take profit price
  3. Open a short futures position with both attached

For now we'll use the trigger candle's own range (high − low) as our volatility measure. We'll improve this with ATR in the next section.

The math:

  • candle_range = high − low (of candle 0, the trigger red candle)
  • sl_price = high + candle_range (one full range above the high)
  • tp_price = close − 2 × candle_range (two full ranges below the close — a 1:2 risk-reward)

Building the trade body

Inside the trade If's body:

  1. Compute candle_range:

    • Set Variable candle_range to ___
    • In the value slot: Math: a − b
    • Left: Candle [0] bars ago value [High]
    • Right: Candle [0] bars ago value [Low]
  2. Compute sl_price:

    • Set Variable sl_price to ___
    • Math: a + b — left is Candle [0] bars ago value [High], right is Get variable candle_range
  3. Compute tp_price:

    • Set Variable tp_price to ___
    • Math: a − b — left is Candle [0] bars ago value [Close], right is a nested Math: a × b with Value 2 and Get variable candle_range
  4. Open the short:

    • From Trading, drag Open Position. Set side to Short.
    • For the amount, drag Get variable collateral.
    • In the options chain, attach stop_loss (with Get variable sl_price) and take_profit (with Get variable tp_price).

When you're done, your trade body looks like this (the variables are computed, then the order is placed using them):

Trade body with candle range

The full trade block: compute candle_range from the trigger candle's high − low, derive sl_price and tp_price from it, then open a short with both attached.

Compute into variables, then reference

You could nest all the math directly inside the Open Position block's stop_loss and take_profit slots. We chose to store them in named variables first because:

  • sl_price and tp_price describe what the value means, making the strategy easier to read
  • If something goes wrong, you can inspect the variables in the backtest log
  • If you want to use the same value in two places (e.g. logging both), you only compute it once

Chaining the stacks together

Right now we have three separate stacks. Their order matters, and there's no UI cue telling you that. The cleanest fix: chain them. Connect the bottom of the init stack to the top of the trade stack, and the bottom of the trade stack to the top of the flag-bookkeeping stack. Now you have one continuous block, and execution order is physically encoded.

Strategy with all blocks chained together

The full strategy as a single chain: init → trade-check → flag-reset → flag-set. Each section is its own coloured block group, but they're all wired in the order they execute.

Click Create Strategy at the bottom of the dialog. The dialog closes; the strategy appears in the Strategies panel on the right.

Running the first backtest

Open the Backtesting panel (below Strategies and Statistics in the right sidebar — you may need to scroll). Click New Backtest.

New backtest dialog

The backtest dialog. Strategy is pre-selected. Set a start date that gives the strategy enough data to fire multiple times — for 12h candles on a 4-month period, ~180 bars, plenty of opportunities.

Settings:

  • Start Date/Time: 2026-01-01T00:00
  • Initial Capital: $10,000
  • Commission: 0.001 (0.1% — matches typical exchange reality)

Click Run Test.

Reading the results

Here's what came back:

Backtest results — first iteration

MetricValue
Total Return−0.35%
Number of Trades9
Win Rate55.56%
Win/Loss Ratio1.25
Profit Factor0.90
Max Drawdown−10.13%
Avg PnL per trade−$11.64

A few things to notice:

The strategy fires. 9 trades over ~4 months — that's a real signal, not noise. The hypothesis isn't garbage.

The win rate is positive. 55.6% of trades are winners. More than half. Sounds great.

But the profit factor is 0.90. This is the key number. Profit factor is total winnings ÷ total losses. A value below 1.0 means you lose more on losers than you make on winners — even with a positive win rate. 0.90 means for every $1 in losses, you only make $0.90 in winnings.

The result: a slightly losing strategy. Win rate alone doesn't determine profitability. Win/loss ratio matters as much.

The lesson the trading mindset page hinted at

A strategy isn't about being right more often. It's about expectancy: how much you win on average per trade, given both the win rate AND the win/loss ratio.

expectancy = (win_rate × avg_win) − (loss_rate × avg_loss)

If your wins and losses are roughly the same size, you need a clear win-rate edge. If your wins are much larger than your losses, you can be profitable with a low win rate. If your wins are much smaller than your losses, even a high win rate isn't enough.

So this version of the hypothesis didn't pan out. Now we iterate.

Iteration 1: Replace candle range with ATR

The single-candle range we used as our volatility measure is noisy. The trigger candle could be unusually tiny (and our stop is too tight) or unusually huge (and our stop is too wide). Either way, the stop placement doesn't reflect the asset's typical volatility — just whatever happened in that one candle.

ATR (Average True Range) is a 14-period (by default) average of candle ranges. It smooths out the noise. Same idea, more stable estimate.

Create an ATR indicator

In the right sidebar, click New Indicator. Name it BTC 12h ATR, type ATR, and the exchange/symbol/timeframe should pre-fill to match your strategy. Click Create Indicator.

New indicator dialog

The ATR indicator dialog. The defaults (Binance, BTC/USDT, 12h, period 14) are exactly what we want.

A new pane appears below the price chart showing the ATR line.

Edit the strategy to use ATR

Click on your strategy in the Strategies panel to re-open the editor. Inside the trade body, delete the candle_range calculation entirely — we won't need it. Then update sl_price and tp_price to use the ATR value directly:

  • sl_price = high + (ATR × 0.7)
  • tp_price = close − (ATR × 4.0)

Wait — those multipliers (0.7 and 4.0) aren't the 1:2 ratio we started with. They give roughly 1:5.7 risk-reward instead. Why?

We tuned them. By trial and error, we found these multipliers gave the best in-sample backtest. Read on.

Strategy with ATR-based SL/TP

The same strategy with ATR-based stops. SL is 0.7 × ATR above the high; TP is 4 × ATR below the close. The candle_range variable is gone — we don't need it anymore.

Re-run the backtest

Same date range (Jan 1 → now), same capital, same commission:

ATR-tuned backtest results

Metricv1 (candle range)v2 (ATR, tuned)
Total Return−0.35%+10.57%
Trades98
Win Rate55.6%50%
Win/Loss Ratio1.251.0
Profit Factor0.902.20 ↑↑
Max Drawdown−10.13%−9.14%
Avg PnL per trade−$11.64+$132.08

Now this is interesting. The win rate went down (55.6% → 50%), but the strategy went from losing to winning. By widening the take profit relative to the stop loss, each winner pays for more losers. Even at break-even win rate, the strategy is profitable because gross profit is 2.2× gross loss.

This is exactly the expectancy lesson from above. Lower win rate, higher win/loss ratio, better outcome.

The honest truth about tuning

We didn't pick 0.7 and 4.0 from theory. We tweaked them until the backtest looked good. That's curve-fitting. Curve-fitting means finding parameters that fit a specific dataset — not parameters that capture a general truth about the market.

The risk: a strategy that's tuned to one period might fall apart on a different period. The "edge" you found wasn't real; it was just noise that happened to favour those specific numbers.

How beginners blow up

Most retail strategies that "look great" in a backtest were tuned this way. The trader saw a 50% loss in their first month live and concluded the market had "changed." It hadn't — they were never trading a real edge in the first place. They were trading noise that fit their backtest.

Always run an out-of-sample test before believing a backtest.

Out-of-sample testing

The honest test: run the same strategy with the same parameters on a different time period the strategy wasn't tuned on. We tuned on Jan→Apr 2026. Let's run on Jan 2025 → now (~16 months including the tuning period as a portion of it):

Out-of-sample backtest 2025

MetricIn-sample (~4 months)Out-of-sample (~16 months)
Total Return+10.57%+21.12%
Trades831
Win Rate50%38.71%
Win/Loss Ratio1.00.63 ↓
Profit Factor2.201.48
Max Drawdown−9.14%−17.08% ↑↑
Calmar Ratio1.161.24
Max Consecutive Losses28

The strategy survived. Profit factor is still > 1.0. Total return is positive. Most overfit strategies completely break out-of-sample — this one didn't. That's a good sign that there's a real (if small) edge here.

But every quality metric got worse:

  • Win rate dropped (50% → 38.7%)
  • Win/loss ratio dropped (1.0 → 0.63)
  • Profit factor dropped (2.20 → 1.48)
  • Max drawdown almost doubled (−9.1% → −17.1%)
  • 8 consecutive losing trades at one point — a real psychological test

The +21% over 16 months is roughly 14% annualized. Not amazing, not bad. Better than most savings accounts; worse than holding BTC outright over the same period.

The realistic read

The in-sample numbers were flattering. The out-of-sample numbers are closer to what you'd actually experience trading this live. Always weight the worse number more heavily — that's the honest expectation. If you can stomach a 17% drawdown and 8 losses in a row, this strategy might be worth running. If you'd close it after 4 losses, you'll lock in your loss right before a recovery, and you'd have been better off not running it at all.

What you've built

In this tutorial you went from "I see a pattern on the chart" to "here's a backtested, out-of-sample-tested strategy with realistic performance expectations." Along the way:

  • You converted an observation into a concrete rule. No vibes; the rule has specific entry, exit, and sizing criteria.
  • You learned the init pattern. Is first run + execute_if is how you do one-time setup in BrighterTrading.
  • You hit a logical contradiction and solved it with state. The flag pattern is a general tool — any time you need to remember something across ticks, this is the shape.
  • You ran a backtest, found the strategy unprofitable, and iterated. The first version of any strategy almost never works. Iteration is the whole game.
  • You used an indicator. ATR for volatility-based stop sizing; you could swap in any of the other indicators the same way.
  • You learned what curve-fitting looks like and how to test for it. Out-of-sample is non-negotiable.

Where to go from here

Before running this strategy in paper mode (let alone live), consider:

  1. Test on more periods. 2024. 2023. Bear markets vs bull markets. Does it hold up?
  2. Try other parameter combinations. Maybe 0.5 × ATR for SL and 3 × ATR for TP works just as well or better. Don't trust a single set of multipliers.
  3. Try other timeframes. Does the streak pattern work on 4h? 1d? 1w? Each timeframe is its own market.
  4. Try other assets. Does it work on ETH? SOL? Total altcoins? If it only works on BTC, that's suspicious — real edges often generalize.
  5. Paper trade it. Run it forward in paper mode for a month. Backtest results don't always match live behaviour because backtests assume perfect fills.
  6. Decide if you can stomach the drawdown. A 17% drawdown means at some point you'll be looking at a $1,700 loss on a $10k account. If that's going to make you turn it off, run it smaller or don't run it at all.

That's the honest workflow. Build, backtest, iterate, out-of-sample, paper, live — in that order, with the discipline to stop at any step where the numbers tell you to.