Position Sizing & Trade Delays
Control how much you trade with SetPositionSize, and when fills happen with SetTradeDelays and SetOption.
- ·SetPositionSize modes
- ·Percent of equity vs fixed
- ·spsShares / spsValue
- ·SetTradeDelays explained
- ·Initial equity & commissions
- ·Margin & leverage
We can now enter, exit, and protect a trade with stops. Two questions remain before a backtest means anything: how much do we trade on each signal, and when exactly does the order fill? Get sizing wrong and a brilliant strategy can blow up; get the fill timing wrong and your backtest quietly cheats by buying at prices you could never have reached.
Because AmiBroker's backtester is portfolio-aware, SetPositionSize can juggle sizing across a whole basket of symbols sharing one equity pool - not just one symbol at a time.
Both are one-line settings in AmiBroker, but they carry a lot of weight. This chapter covers SetPositionSize for the "how much", SetTradeDelays for the "when", and the account settings - starting capital, commissions and margin - that make the whole simulation honest.
SetPositionSize: how much to trade
SetPositionSize(amount, mode) tells the backtester how big each position should be. The second argument, mode, decides how the first one is read:
spsPercentOfEquity-amountis a percent of current equity.SetPositionSize(75, spsPercentOfEquity)puts 75% of your account into each trade. As the account grows, position size grows with it (compounding).spsShares-amountis a fixed number of shares/contracts.SetPositionSize(100, spsShares)always buys 100 shares, whatever the price.spsValue-amountis a fixed rupee value.SetPositionSize(100000, spsValue)puts Rs 1,00,000 into every trade regardless of account size.spsNoChange- keep the previously set size; useful when you only want to change sizing on some bars.
Here is the sizing line from the author's 10 and 20 EMA Crossover.afl:
SetPositionSize(75, spsPercentOfEquity); // risk 75% of equity per trade
To feel the difference, take the same Buy on a stock priced at Rs 1,318, with Rs 10,00,000 of equity. The three modes commit wildly different amounts:
| Mode | Setting | Money committed | Shares bought |
|---|---|---|---|
spsShares |
SetPositionSize(100, spsShares) |
Rs 1,31,800 | 100 |
spsValue |
SetPositionSize(100000, spsValue) |
Rs 1,00,000 | 75 |
spsPercentOfEquity |
SetPositionSize(75, spsPercentOfEquity) |
Rs 7,50,000 | 569 |
Same signal, same price - three completely different trade sizes. spsShares buys a flat 100 shares whatever the cost; spsValue works backward from a fixed rupee budget (Rs 1,00,000 / Rs 1,318 is about 75 shares); and spsPercentOfEquity commits a slice of the whole account (75% of Rs 10,00,000 buys about 569 shares). That choice, more than the entry rule, often decides whether a system compounds smoothly or lurches.
Percent-of-equity vs fixed sizing
The choice of mode changes the shape of your equity curve, not just its height:
- Percent of equity compounds. Winners make the next position bigger, so a good run snowballs - and a bad run shrinks positions, cushioning the fall. This is the realistic way most systematic traders size, and it is what makes a backtest curve bend upward exponentially.
- Fixed shares or fixed value does not compound. Every trade is the same size, so the equity curve grows in a straight line. This is excellent for analysis - it shows the raw, per-trade edge of the system without the flattering curve of compounding masking a weak run.
A good habit while developing: test with a fixed size first to see the honest edge, then switch to percent-of-equity to see how it compounds.
Sizing mode is not a detail - it changes the story the backtest tells. spsPercentOfEquity compounds and flatters; spsShares/spsValue stay flat and reveal the bare edge. Judge a new system on a fixed size first, then admire the compounding second.
SetTradeDelays: when orders fill
SetTradeDelays(buy, sell, short, cover) postpones each kind of fill by a whole number of bars. The four arguments map one-to-one to the four reserved arrays:
SetTradeDelays(1, 1, 1, 1); // fill one bar AFTER each signal
This says: when a signal appears on a bar, do not fill on that bar - wait one bar and fill then (at that next bar's price). This models reality: you see the signal at the close, you act on the next bar.
There are two clean ways to get a realistic next-bar fill, and you must pick exactly one:
- Engine delay. Keep signals on the cross bar and set
SetTradeDelays(1, 1, 1, 1). AmiBroker shifts the fills for you. - Manual delay. Delay the signals yourself with
Ref(..., -1)(Chapter 21) and setSetTradeDelays(0, 0, 0, 0)so the engine adds nothing.
Both land the fill on the next bar. What you must never do is both at once - that double-delays every trade.
Decide your delay style once and stick to it. Manual Ref(..., -1) pairs with SetTradeDelays(0,0,0,0); engine delay pairs with signals left on the cross bar. Combining a manual Ref(-1) with SetTradeDelays(1,1,1,1) shifts every fill two bars late and silently corrupts the report.
When the fill lands on the next bar, remember to price it there too - BuyPrice = ValueWhen(Buy, Open) fills at that next bar's open, the honest price.
Starting capital and commissions
A backtest needs to know how much money it starts with and what trading costs. These are SetOption calls:
SetOption("InitialEquity", 1000000); // start with Rs 10,00,000
SetOption("CommissionMode", 2); // 2 = a flat amount per trade
SetOption("CommissionAmount", 20); // Rs 20 per executed order
InitialEquity is your starting capital - it anchors every percentage in the report and is what spsPercentOfEquity sizes against. CommissionMode chooses how costs are charged: mode 1 reads CommissionAmount as a percentage of trade value, while mode 2 reads it as a flat fee per trade. Always include a realistic cost - a strategy that looks great at zero commission can turn unprofitable once brokerage and charges are deducted, especially a high-frequency intraday one.
You can set these in the Settings dialog instead of in code (we open it next chapter). Putting them in the AFL has one big advantage: the assumptions travel with the formula, so anyone who runs your file gets the same starting capital and costs - no hidden settings to forget.
Margin and leverage
By default a backtest assumes you pay the full value of every position in cash. Futures and intraday trades use leverage - you post only a fraction as margin. AccountMargin models this:
SetOption("AccountMargin", 100); // 100 = no leverage, fully funded
The number is the percentage of a position's value you must put up as margin. 100 means you fund trades fully (cash equities). 50 means you only post half, giving 2x leverage; 20 means a fifth, giving 5x. Lower margin lets the same capital control a bigger position - which magnifies both profit and loss, and deepens drawdowns. Set it to match the instrument you are actually trading: 100 for delivery equities, a smaller figure for index futures.
// A realistic intraday-futures account header
SetOption("InitialEquity", 1000000);
SetOption("CommissionMode", 2);
SetOption("CommissionAmount", 40);
SetOption("AccountMargin", 20); // 5x leverage on futures
SetPositionSize(50, spsPercentOfEquity);
SetTradeDelays(0, 0, 0, 0); // we delay signals with Ref(-1)
That header block is worth saving as a template: drop it at the top of any system and you have realistic starting capital, costs, leverage and sizing in six lines - the difference between a backtest you can trust and a flattering fantasy.
Try it yourself
- Add
SetPositionSize(100, spsShares)to your EMA system, backtest, then switch toSetPositionSize(75, spsPercentOfEquity)and compare the shape of the two equity curves. - Set
SetOption("CommissionAmount", 0)then100and watch net profit fall - costs are not optional. - Change
AccountMarginfrom100to25and observe how leverage stretches both the gains and the drawdown. - Deliberately set
SetTradeDelays(1,1,1,1)while your signals already useRef(..., -1), then revert. Note how the entry prices shift.
Recap
SetPositionSize(amount, mode)sets trade size:spsPercentOfEquity(compounds),spsShares(fixed count),spsValue(fixed rupees),spsNoChange(keep prior).- Percent-of-equity flatters with compounding; fixed sizing reveals the bare per-trade edge - use both while developing.
SetTradeDelays(buy, sell, short, cover)shifts fills by whole bars; pick either engine delay or manualRef(..., -1), never both.SetOption("InitialEquity", ...)sets starting capital;CommissionMode/CommissionAmountset realistic costs.SetOption("AccountMargin", ...)models leverage -100is fully funded, lower numbers magnify gains, losses and drawdown.
Next, we put every one of these pieces to work - running our first full backtest in the Analysis window and reading the equity curve it produces.