Skip to content
Level 4 · Trading System ResearcherLessonPart 33 · page 2 of 426 min
26Minutes
12AFL functions
6Sources
StandardRequires
AFL functions taught here12

The AmiBroker Monte Carlo Workflow

If you have run a portfolio backtest in AmiBroker, you have already run a Monte Carlo simulation, whether or not you meant to. The simulator is enabled by default for portfolio backtests, which is why an unrequested “Monte Carlo” page keeps appearing in reports. This lesson turns that accident into a procedure: what each control does, which two of them change the answer rather than the picture, how to read the output page in the direction it is actually written, and where the documented feature stops.

In the New Analysis window, open Settings and go to the Monte Carlo tab — the last one, after Walk-Forward. Nothing there runs on its own. The simulation happens when you press Backtest, immediately after the trade list has been generated, and the guide notes that it usually costs a fraction of a second on top of the backtest itself.

The results appear on the Monte Carlo page of the backtest report, alongside the statistics and trade list pages you already know from Part 29.

Field on the tab SetOption() field What it changes
Enable Monte Carlo simulation "MCEnable" 0 off; 1 on for portfolio backtests, the default; 2 on everywhere including optimization
Number of runs "MCRuns" Realizations to generate. Default 1000; the guide asks for 1000 or more
Simulate using portfolio equity changes "MCUseEquityChanges" set to 1 Resamples bar-by-bar equity percentage changes
Simulate using trade list "MCUseEquityChanges" set to 0 Resamples individual closed trades
Position sizing "MCPosSizeMethod" 0 don’t change; 1 fixed size; 2 constant amount; 3 percent of equity
— shares/contracts "MCPosSizeShares" The share count used by method 1
— cash amount "MCPosSizeValue" The cash amount used by method 2
— percent "MCPosSizePctEquity" The percentage used by method 3
Enable MC equity curves "MCChartEquityCurves" Draws the min/max/average and straw-broom chart
Straw broom chart plots "MCStrawBroomLines" How many individual equity lines to draw, 0 to 100
Use logarithmic scale for Final equity "MCLogScaleFinalEquity" Chart scaling only
Use logarithmic scale for $ Drawdown "MCLogScaleDrawdown" Chart scaling only
Use negative numbers for Drawdown "MCNegativeDrawdown" Reverses the sign and the meaning of the drawdown columns

Two of those change what is computed. The rest change how it is drawn or how many times it is done.

The previous lesson covered why: bootstrapped trades are replayed sequentially, so a system whose positions overlapped in reality gets its simultaneous losses spread out and its drawdown understated. The guide’s recommendation is a straight fork — trade-list mode for systems with non-overlapping trades, equity-changes mode for systems with simultaneous positions.

Equity-changes mode has a second, quieter advantage: it needs no position-sizing decision at all, because it resamples ratios. A bar that gained ten per cent is 1.1 whatever the account was worth at the time, and the ratios are simply multiplied together in the drawn order.

The position-sizing group is where the subtle mistakes live.

Don’t change sounds like the safe option and is the one most likely to surprise you. The guide states that it always uses the original cash value of each trade — even when your formula sized positions as a percentage of portfolio equity. A system that put ten per cent of a growing account into each trade produces trades whose cash sizes grew over the years, and the bootstrap will replay those cash amounts in an order that no longer has anything to do with the account balance that justified them.

Percent of equity looks like the sophisticated option and carries an explicit warning in the documentation. It makes each simulated trade’s size depend on the profits of the simulated trades before it, which is serial dependence — precisely the property a bootstrap exists to remove. The guide restricts its use to systems with no overlapping trades and warns of an additional compounding distortion otherwise.

The documented best practice is the dull one: use fixed sizing, either a fixed share count or a fixed cash amount, so that a trade’s contribution does not depend on where in the sequence it lands. That is what makes the resampling clean, and it is also why the numbers on the Monte Carlo page do not have to agree with the equity curve on the report’s own charts.

Use negative numbers for Drawdown (reverse Drawdown CDF) does more than change a sign. It reverses the ordering of the drawdown column and inverts what a percentile means.

Setting Drawdowns shown as A 10th-percentile drawdown means
OFF Positive numbers A 10 per cent chance of drawdowns equal to or better (smaller) than that value
ON Negative numbers A 10 per cent chance of drawdowns equal to or worse (more negative) than that value

Same simulation, same data, opposite reading. The option has been on by default since AmiBroker 6.10, which means anything you read about interpreting the drawdown column written against an older version may be describing the other convention. Check the setting before you interpret the table, every time.

A portfolio system that is unremarkable on purpose, with every assumption written at the top and every Monte Carlo setting applied in code, so that the run can be repeated exactly by anyone who has the file. This is the system the rest of Part 33 resamples.

Complete runnable AFL

mc-baseline-system.afl
// mc-baseline-system.afl
// Part 33 - Monte Carlo and Robustness
//
// A deliberately ordinary long-only portfolio system. It exists so that Part 33
// has a trade list and an equity curve to resample. Nothing in it is a
// recommendation, and no result it produces is evidence that the rules work.
//
// ASSUMPTIONS - quote these with every number this formula produces:
// Universe .......... the watch list you select in the Analysis window.
// Interval .......... daily bars, end-of-day data.
// Signal delay ...... 1 bar on every signal (SetTradeDelays below).
// Fill price ........ the next bar's open, moved against us by SlippagePct.
// Commission ........ 0.10 per cent of trade value, charged on each side.
// Liquidity ......... 50-day average turnover must exceed LiquidityFloor.
// Capital ........... 100,000 starting equity, at most 10 open positions,
// 10 per cent of portfolio equity committed per position.
// Not modelled ...... market impact, borrowing costs, dividends, taxes,
// corporate actions, and any survivorship bias that is
// already baked into your database.
//
// Run it as a portfolio Backtest in the New Analysis window. The Monte Carlo
// settings below are applied from the formula so that the run is reproducible
// and the settings travel with the file instead of living in a dialog.
// ---- Account and backtester settings -------------------------------------
SetOption( "InitialEquity", 100000 );
SetOption( "MaxOpenPositions", 10 );
SetOption( "CommissionMode", 1 ); // 1 = commission as percent of trade
SetOption( "CommissionAmount", 0.10 ); // charged on entry and on exit
SetOption( "AllowPositionShrinking", True );
SetBacktestMode( backtestRegular );
SetTradeDelays( 1, 1, 1, 1 );
SetPositionSize( 10, spsPercentOfEquity );
// ---- Monte Carlo settings -------------------------------------------------
// Every field here is documented on the Monte Carlo page of the User's Guide.
// MCUseEquityChanges is the important one: this system holds up to ten
// positions at once, so the trade-list bootstrap would replay overlapping
// trades sequentially and under-report drawdown. Resampling bar-by-bar
// portfolio equity changes is the mode the guide prescribes for that case.
SetOption( "MCEnable", 1 ); // 1 = run MC on portfolio backtests
SetOption( "MCRuns", 5000 ); // the guide asks for 1000 or more
SetOption( "MCUseEquityChanges", 1 ); // 1 = equity changes, 0 = trade list
SetOption( "MCChartEquityCurves", 1 );
SetOption( "MCStrawBroomLines", 50 );
SetOption( "MCNegativeDrawdown", 1 ); // drawdowns reported as negative
// ---- Costs the backtester will not charge for you -------------------------
// Commission is a setting; slippage is not. We pay it by moving every fill
// away from us before the backtester sees the price.
SlippagePct = 0.05;
// ---- Rules ----------------------------------------------------------------
FastPeriod = 20;
SlowPeriod = 100;
TrendPeriod = 200;
LiquidityFloor = 2000000; // 50-day average turnover, database currency
Turnover = MA( Close * Volume, 50 );
Liquid = Turnover > LiquidityFloor;
FastAvg = MA( Close, FastPeriod );
SlowAvg = MA( Close, SlowPeriod );
TrendAvg = MA( Close, TrendPeriod );
// A setup is a state: the instrument is in a long-term advance and is liquid
// enough that our fill assumption is not absurd. The trigger is an event.
Setup = Close > TrendAvg AND Liquid;
Trigger = Cross( FastAvg, SlowAvg );
Buy = Setup AND Trigger;
Sell = Cross( SlowAvg, FastAvg );
Short = False;
Cover = False;
// A maximum-loss stop, checked on the closing price only. Checking High-Low
// and filling exactly at the stop level would assume an intrabar fill nobody
// can promise us; Part 28 explains why that flatters results.
ApplyStop( stopTypeLoss, stopModePercent, 15, 0 );
// When more symbols signal than we have capital for, the backtester keeps the
// highest-scoring ones. Ranking by 100-bar rate of change makes the choice
// explicit and repeatable rather than alphabetical.
PositionScore = ROC( Close, 100 );
// Fills, moved against us on both sides.
BuyPrice = Open * ( 1 + SlippagePct / 100 );
SellPrice = Open * ( 1 - SlippagePct / 100 );

Download mc-baseline-system.afl89 lines

The first block sets up the account: starting equity, a cap of ten open positions, commission as a percentage charged on both sides, and one bar of delay on every signal so that nothing is acted on at a price that was not yet knowable.

The second block configures the simulator. "MCUseEquityChanges" set to 1 is the important line — this system holds up to ten positions, so the trade-list bootstrap would understate its drawdown. "MCNegativeDrawdown" is set explicitly rather than left to the default, so that the report’s convention is a documented property of the file rather than a property of whichever machine it is run on.

The rules themselves are the least interesting part, which is deliberate. A long-term average defines the state that makes an instrument a candidate; a faster crossover provides the event that turns a candidate into an entry; a turnover floor keeps the universe to instruments where filling at the open is not an absurd assumption. When more symbols signal than there is capital for, PositionScore decides which ones are taken, so the choice is explicit and repeatable rather than an artefact of symbol ordering.

The last block pays for slippage by hand. Commission is a backtester setting; slippage is not, so every fill is moved against us by a fixed fraction before the backtester ever sees the price.

  • SetOption( "MCEnable", 1 ) and its companions — the whole Monte Carlo tab, expressed in code. The fields "MCUseEquityChanges", "MCChartEquityScale", "MCLogScaleFinalEquity", "MCLogScaleDrawdown" and "MCNegativeDrawdown" were added in AmiBroker 6.10 and are documented on the Monte Carlo page rather than in the SetOption() function reference.
  • SetPositionSize( 10, spsPercentOfEquity ) — commits ten per cent of portfolio equity per position. Covered properly in Part 28.
  • SetTradeDelays( 1, 1, 1, 1 ) — one bar of delay on every signal array.
  • PositionScore — the reserved variable the backtester ranks competing signals by.

A backtest report with a Monte Carlo page containing a percentile table, a min/average/max equity chart with fifty straw-broom lines behind it, and a set of cumulative distribution charts. The specific numbers depend entirely on your database, your universe and your date range, so there is no figure here for you to match — and if there were, matching it would prove nothing.

What you should check is structural: the Settings section of the report should show the Monte Carlo options you set in code, the number of realizations should be 5,000, and the drawdown column should be negative.

Change "MCRuns" from 5000 to 200 and re-run. The percentile table should shift noticeably between repeated 200-run tests and barely at all between repeated 5,000-run tests; that difference is sampling noise in the simulator, and watching it settle down tells you how many runs your own conclusions need.

Then flip "MCUseEquityChanges" to 0 and compare the drawdown column with the Max. system % drawdown on the report’s statistics page. For a system holding ten positions the trade-list figures should come out milder, which is the sequential-replay effect made visible on your own data.

  • Setting the options in the dialog and in the formula. The formula wins, silently. If the tab shows something different from what the report says, the formula is the culprit.
  • Leaving "MCEnable" at 2. It forces the simulation to run on every optimization step. The guide describes this as capable of increasing optimization time by orders of magnitude, and it is only worth doing when a Monte Carlo percentile is your optimization target.
  • Reading the Monte Carlo drawdown as if it were the report’s drawdown. They are different columns computed from different things. Max. Drawdown % on the Monte Carlo page is a simulated distribution; Max. system % drawdown on the statistics page is what actually happened.
  • Expecting the simulated median to match the backtest. It generally will not, especially with fixed Monte Carlo position sizing, and that is not a bug.

Set "MCStrawBroomLines" to 100 and turn on the logarithmic scale for final equity. On a log scale a straw-broom chart of a compounding system fans out as a roughly symmetrical cone; on a linear scale the same data looks dramatically skewed. Neither picture is wrong, and noticing how much the impression changes with the scale is a useful inoculation against reading equity charts as evidence.

At the top of the page is a table with exactly these columns, at percentile levels 1, 5, 10, 25, 50, 75, 90, 95 and 99:

Percentile · Final Equity · Annual Return · Max. Drawdown $ · Max. Drawdown % · Lowest Eq.

Those labels appear nowhere else in the report. Annual Return here has no per-cent suffix, unlike Annual Return % on the statistics page, and Max. Drawdown $ and Max. Drawdown % are not the same quantities as Max. system drawdown and Max. system % drawdown. Quoting one under the other’s name is a small error that makes a large difference to anyone trying to reproduce your work.

Lowest Eq. is worth a second look, because it is the column that most directly answers a practical question. Maximum drawdown is measured from a peak; lowest equity is measured against the money you started with. A system can have a tolerable maximum drawdown and still spend a year below its starting capital, and it is the second fact that decides whether anyone is still following the rules by the time the edge shows up.

Below the table sits a chart with a green line, a red line, a blue line and a cloud of grey ones. The grey lines are individual realizations. The other three are not equity curves at all: green and red are the bar-by-bar highest and lowest points across all realizations, and blue is the bar-by-bar average.

After the equity chart come cumulative distribution charts for final equity, annual return, dollar drawdown, percentage drawdown and lowest equity. They contain exactly the same information as the percentile table, in graphical form. They are easier to read at a glance and they are not additional evidence; presenting both as though they were two findings is a way of making one weak result look like two.

The Monte Carlo simulator arrived in AmiBroker 6.00. The formula-level fields for the sampling mode, the chart scales and the drawdown sign were added in 6.10, along with the change that made negative drawdown numbers the default. This course is validated against 7.00.1.

The User’s Guide places no edition restriction on Monte Carlo. It is not a Professional feature. What does differ by edition is throughput: the guide states a limit of two threads per Analysis window for the Standard edition and thirty-two for Professional. That has almost no effect on a single backtest with a simulation attached, and a very large effect on anything that runs the simulator inside an optimization.

Which is the cost note worth remembering. On one backtest the simulation is nearly free. With "MCEnable" set to 2 it runs on every optimization step, and the guide’s advice is unambiguous: do not do it unless a Monte Carlo statistic is genuinely your optimization target.

This section exists because a great deal of what is written about “Monte Carlo in AmiBroker” describes third-party add-ons or other platforms entirely.

There is no Monte Carlo function in AFL. Searching the official function index for “monte” returns nothing. The simulator is driven by the Settings dialog, by the SetOption() and GetOption() fields listed above, and by one object in the custom backtester interface.

There is no built-in synthetic price generator, and no dialog anywhere in AmiBroker that randomises trade prices to simulate variable slippage. You can write such a thing yourself by perturbing BuyPrice and SellPrice, and the final lesson shows what that involves, but it is your code rather than a feature.

Randomization is a technique, not a checkbox

Section titled “Randomization is a technique, not a checkbox”

The User’s Guide ends its Monte Carlo chapter with a genuinely different idea. Instead of resampling the trades a backtest took, re-run the backtest many times and let it take different trades, by replacing the analytic PositionScore with a random number. Where a system generates more signals than it has buying power for, that produces a different selection each time.

Find out how much of the result depended on which candidates were taken, rather than on the rules that generated them.

Complete runnable AFL

randomised-position-score.afl
// randomised-position-score.afl
// Part 33 - Monte Carlo and Robustness
//
// Monte Carlo RANDOMIZATION. This is not the built-in bootstrap on the
// Settings -> Monte Carlo tab. It is a formula pattern the User's Guide
// describes at the end of its Monte Carlo chapter, and AmiBroker exposes no
// dialog for it: you get it only by writing the code below.
//
// What it does: instead of resampling the trades a backtest already took, it
// re-runs the whole backtest many times and lets the backtester pick a
// DIFFERENT subset of the available signals each time, by replacing the
// analytic PositionScore with a random number. The Optimize() call is used
// purely as a repeat counter - its value is never read.
//
// WHEN THIS IS MEANINGLESS:
// * If the system rarely produces more signals than it has capital for,
// there is nothing to choose between and nothing to randomise.
// * If ranking IS the strategy - any rotational system, anything that buys
// "the strongest N" - replacing the score with noise tests noise, not the
// system. The guide says so plainly.
// * mtRandom() without a seed is seeded from the clock, so two runs of this
// file will not reproduce each other. Record what you observed, because
// you cannot re-create it exactly.
//
// ASSUMPTIONS - the same as mc-baseline-system.afl, and quote them together:
// Universe .......... a BROAD watch list. On a handful of symbols this
// technique tells you nothing.
// Interval .......... daily bars, end-of-day data.
// Signal delay ...... 1 bar. Fills at the next open, moved by SlippagePct.
// Commission ........ 0.10 per cent of trade value per side.
// Capital ........... 100,000, at most 10 open positions, 10 per cent each.
// Not modelled ...... market impact, borrowing costs, dividends, taxes.
//
// Run it with the Optimize button in the New Analysis window. Each row of the
// result list is one realization: the same rules, a different set of picks.
// Sort by CAR/MDD and look at the spread, not at the top row.
// One "optimization step" = one realization. 200 is enough to see the shape of
// the distribution; raise it once you know how long a single backtest takes.
Realization = Optimize( "Realization", 1, 1, 200, 1 );
SetOption( "InitialEquity", 100000 );
SetOption( "MaxOpenPositions", 10 );
SetOption( "CommissionMode", 1 );
SetOption( "CommissionAmount", 0.10 );
SetBacktestMode( backtestRegular );
SetTradeDelays( 1, 1, 1, 1 );
SetPositionSize( 10, spsPercentOfEquity );
// Monte Carlo bootstrap OFF. Running the built-in simulator inside an
// optimization multiplies its cost by the number of steps, and here it would
// answer a different question from the one we are asking.
SetOption( "MCEnable", 0 );
SlippagePct = 0.05;
Turnover = MA( Close * Volume, 50 );
Liquid = Turnover > 2000000;
FastAvg = MA( Close, 20 );
SlowAvg = MA( Close, 100 );
TrendAvg = MA( Close, 200 );
Buy = Close > TrendAvg AND Liquid AND Cross( FastAvg, SlowAvg );
Sell = Cross( SlowAvg, FastAvg );
Short = False;
Cover = False;
ApplyStop( stopTypeLoss, stopModePercent, 15, 0 );
// The whole point of the file. One random number per symbol per run, so each
// realization ranks the candidate list in a different arbitrary order.
// Swap in mtRandomA() if you want the ranking re-drawn on every bar instead -
// a different experiment, with a different meaning.
PositionScore = mtRandom();
BuyPrice = Open * ( 1 + SlippagePct / 100 );
SellPrice = Open * ( 1 - SlippagePct / 100 );

Download randomised-position-score.afl79 lines

Optimize() is used as nothing but a repeat counter: its value is never read, and each “optimization step” is one complete backtest. mtRandom() returns a single number in the range 0 to 1, and because the formula is executed once per symbol, each symbol receives its own arbitrary constant score for the duration of that run. The backtester ranks the competing signals by that score, so every run keeps a different subset of the available candidates.

  • Optimize( "Realization", 1, 1, 200, 1 ) — declares a variable that steps from 1 to 200, giving 200 backtests. Outside optimization it simply returns its default.
  • mtRandom( seed = Null ) — a Mersenne Twister random number in the range 0 to 1. mtRandomA() is the array version, which would re-draw the ranking on every bar instead of once per symbol: a different experiment with a different meaning.

An optimization result list with 200 rows, one per realization, differing only in which candidates were selected. Read the spread of CAR/MDD down the column, not the top row. The top row of a randomised run is by construction the luckiest draw and means nothing at all.

Run it twice. The two result lists should differ, because mtRandom() without a seed is initialised from the clock. If they are identical, the randomisation is not reaching the backtester and the experiment is not doing anything.

  • Running it on a narrow universe. If the system rarely produces more signals than it can take, there is nothing to choose between and every realization is the same backtest. The guide says plainly to use a large watch list.
  • Running it on a rotational or ranking-driven system. If the score is the strategy, replacing it with noise tests noise. The guide’s own words are that you would be testing white noise rather than the system.
  • Treating the best row as a result. See above; it is the maximum of 200 random draws.
  • Forgetting that it is not reproducible. Without a seed you cannot re-create a specific run, so record the distribution rather than promising to show someone the run again.

Swap mtRandom() for a deliberately bad analytic score — ranking by the worst recent performance, say — and compare where that lands within the distribution of random runs. If your real PositionScore is not comfortably better than the random distribution, the ranking is not earning its place in the system.

The last documented route is the custom backtester. Inside a custom backtest procedure, after bo.Backtest() has run, bo.GetMonteCarloSim() returns a MonteCarloSim object — or nothing at all if the simulation is disabled, which is why the guide’s own example guards the call. That object exposes one method, GetValue( field, percentile ), over exactly five fields: "FinalEquity", "CAR", "LowestEquity", "MaxDrawdown" and "MaxPercDrawdown".

The guide’s worked example builds a robustness-weighted objective by dividing the 30th percentile of CAR by the maximum system percentage drawdown, adds it to the report with bo.AddCustomMetric(), and then uses it as an optimization target. Three things have to be true for that to work, and missing any one of them fails silently: the metric must be added with AddCustomMetric, "MCEnable" must be set to 2 so the simulation runs during optimization, and the metric’s name must be typed exactly into the Optimization target field — which lives on the Walk-Forward tab, even when you are not running a walk-forward test. Part 31 covers that field; Part 36 covers the custom backtester interface in full.

The Monte Carlo tab has thirteen controls, of which two change the answer: the sampling mode and, in trade-list mode, the position-sizing method. Everything else changes the picture or the sample size. Set them from the formula so that a run can be reproduced, and choose equity-changes mode for any system that holds more than one position at a time.

The report page has its own column names, which belong to it alone, and a drawdown column whose meaning is inverted by a checkbox that has been on by default since 6.10. The green and red lines on the equity chart are per-bar extremes across all realizations, not a best and worst case. The distribution charts restate the table rather than adding to it.

Monte Carlo is available in both editions. It is nearly free on one backtest and extremely expensive inside an optimization. And the boundary of the built-in feature is narrow: no AFL function, no synthetic prices, no slippage randomiser. The randomization technique and the custom-metric route are both documented, but both are things you write rather than things you switch on.

Check your understanding

Question 1. A formula contains SetOption("MCRuns", 5000) while the Monte Carlo tab is set to 1000 runs. What happens?
SetOption( "MCRuns", 5000 );
Show the answer and why

Answer: The formula wins; 5000 runs are performed

SetOption() sets Analysis settings from the formula, overriding the dialog for that run. This is a feature rather than a hazard, provided you know it: it is what lets a run be reproduced from the file alone. The hazard is only when you have forgotten the line is there.

Question 2. With "Use negative numbers for Drawdown" turned ON, the 1st-percentile Max. Drawdown % is −58 per cent. What does that say?
Show the answer and why

Answer: One per cent of realizations had a drawdown worse than 58 per cent

With the option on, drawdowns are negative and the ordering is reversed, so the low percentiles are the pessimistic end: a 1 per cent chance of a drawdown equal to or worse than the value shown. With the option off, the same data would be printed as positive numbers with the opposite reading.

Question 3. Which of these are things AmiBroker’s built-in Monte Carlo simulator does NOT do? Select all that apply.
Show the answer and why

Answer: Generate synthetic price series, Randomise slippage on each simulated fill, Randomise the values of parameters declared with Optimize()

The documented scope is bootstrapping the realised trade list or the bar-by-bar portfolio equity changes. Synthetic prices, randomised slippage and randomised parameters are not part of the feature; the first and second can be approximated with your own AFL, but presenting them as built-in capabilities misdescribes the product.

Question 4. Why does the guide warn against "Percent of equity" as the Monte Carlo position-sizing method?
Show the answer and why

Answer: It makes each simulated trade’s size depend on the profits of the trades before it, reintroducing the serial dependence the bootstrap exists to remove

Compounding within a realization couples the trades together, so a trade’s contribution depends on where it lands in the sequence. The documented best practice is fixed sizing — a fixed share count or a fixed cash amount — so that the resampling stays clean.

Question 5. Randomising PositionScore with mtRandom() is most likely to produce a meaningless result on which kind of system?
Show the answer and why

Answer: A rotational system that holds the top-ranked symbols by relative strength

When ranking is the strategy, replacing the score with a random number does not perturb the system, it replaces it. The guide is explicit that you would then be testing white noise. The technique needs a system where selection is a side-effect of limited capital rather than the source of the edge.

Sources for this lesson

6 verified · checked 2026-08-31

  1. 01AmiBroker User's Guide — Monte Carlo simulationamibroker.com/guide/h_montecarlo.html2026-08-31
  2. 02AFL Function Reference — SetOptionamibroker.com/guide/afl/setoption.html2026-08-31
  3. 03AFL Function Reference — mtRandomamibroker.com/guide/afl/mtrandom.html2026-08-31
  4. 04AmiBroker User's Guide — Portfolio Backtester Interface Reference§ MonteCarloSim objectamibroker.com/guide/a_custombacktest.html2026-08-31
  5. 05AmiBroker User's Guide — What's new§ Highlights of version 6.00; change log for 6.10.0amibroker.com/guide/whatsnew.html2026-08-31
  6. 06AmiBroker User's Guide — Multithreadingamibroker.com/guide/h_multithreading.html2026-08-31

Every technical claim on this page was checked against the official AmiBroker documentation on the date shown. Where the course disagrees with folklore, the source is how you can tell which one to trust.