Testing trading strategies on historical data
A reliable portfolio backtest. Quant-research level
hamster-bot/tester - an advanced tool for testing trading systems on historical data.
Backtester features:
- Portfolio test. Several strategies of different types on different pairs and timeframes at once — on a single shared balance. You can see how the strategies coexist on one account: total deposit load, overall drawdown, overlapping positions.
- The same production code. The backtest runs the same code the bot trades with in real time: strategies, position service, position limiter, account options. No rewriting of logic for the tester.
- Honest simulation inside the candle. The strategy is called on every change of the forming candle. Trailing stops, moving orders and exits inside the candle work just like in live trading.
- Realistic costs. Maker/taker fees, slippage and delay of market and stop orders, funding, limit order fills capped by candle volume.
- Data is downloaded automatically. BYBIT, BINANCE, MEXC and others — for any historical period. You can also supply your own data in CSV.
- Detailed interactive report. Equity curve, monthly returns heatmap, trade charts for each pair and more than 50 metrics: Sharpe, Sortino, Calmar, CAGR, Recovery Factor, win/loss streaks, deposit load, etc. Overfitting checks. Monte Carlo over trades, PnL without the best trades and without the best pair, top 5 drawdowns with duration and recovery time, MAE/MFE of every trade, results by hour, day of week and market regime, distance to liquidation.
- Parameter optimizer. Sweep any settings of the bot, strategies, account and the tester itself. Parallel runs on all cores, Monte Carlo sampling for huge parameter spaces, portfolio pair selection without repeats. Results — in a summary table and on heatmaps / 3D surface.
- Robustness checks. Walk-forward (optimize on one part of history, check on another), parameter plateau map, one-click stress test, comparison of several runs and results by market regime (uptrend, downtrend, range, volatility).
- Testing your own complex logic that can't be accurately tested with off-the-shelf third-party solutions without workarounds.
Implemented as a separate connector
to an "exchange" (a mock object replacing the exchange). This way, all the bot's
already-written code can be tested. The bot thinks it's working on a real exchange (places orders, gets balance and
position info). And this virtual exchange stub calculates everything and generates the report.
How to use it
(step by step)
Below is the sequence of steps from the first run to parameter tuning. See the sections below for details on each parameter.
What you need.
— the latest version of hamster-bot installed (the tester is built into the bot, nothing else to install);
— an internet connection to download historical data and instrument parameters from the exchange;
— strategy settings files in the
folder
tester/settings_strategy. The tester does not need API keys or the accounts from
settings_accounts.
The tester never sends orders to a real exchange: the bot works with a virtual exchange instead. Only public
data is taken from the exchange — trade history and instrument parameters (price step, minimum lot, etc.),
which are cached in tester/data/{exchange}/_markets.
Step 1. Prepare the strategies.
The tester has its own settings folder, tester/settings_strategy, separate from the live
settings_strategy. The test does not touch the bot's live settings, and experiments in the tester
do not affect trading. Adding, copying, editing and deleting tester settings is easiest in the web interface
("Tester" tab → "Parameters", see step 3), but you can also just drop .json files into the folder.
Settings can be split into subfolders, for example tester/settings_strategy/trend and
tester/settings_strategy/grid, and you can switch between these sets in the web interface (the
Settings folder line above the table). The table, adding settings and runs work with the selected
folder, without its subfolders. From the console the tester reads only the root of
tester/settings_strategy.
Each file in tester/settings_strategy is one strategy on one pair. Check in it:
— exchange.name — the exchange the data will be downloaded from (bybit,
binance, mexc, bitmex, etc., see the "Market data" section);
— the tester ignores the exchange.account field: all strategies run on a single tester account
from config_tester.json (the accounts section, see "Tester parameters");
— basic.symbol and basic.time_frame — pair and timeframe;
— lot size and strategy settings — the same as for live trading;
— if needed, a separate trading window for this strategy within the overall test (the tester
section in the settings file):
"tester": { "StartDate": "2026-02-01T00:00:00", "EndDate": "2026-02-20T00:00:00" }
Before StartDate the strategy does not trade; after EndDate the tester cancels its
orders and closes its position at market once, and the pair does not trade after that. Either field can be
omitted, in which case there is no limit on that side. Handy when a pair was listed on the exchange after the
test start, was delisted, or when you want to test a portfolio where strategies were added at different
times.
When launched from the console, all files
from tester/settings_strategy go into the test at once — this is a portfolio test on one shared
balance. In the web interface the strategies for a test, parameter mining and stress test are ticked in the
tester wizard (step 3).
Step 2. Configure config_tester.json.
The file is in the bot's folder. If it is missing, it is created with default values when the bot starts (just like settings_program.json).
You can edit it in a text editor or in the bot's web interface ("Tester" tab → "Parameters" →
"Edit config_tester.json", which also has hints for every parameter).
For the first test it is enough to set:
"name_comment": "first_test", "InitialBalance": 1000.0, "StartDate": "2026-01-01T00:00:00", "EndDate": "2026-03-01T00:00:00", "WarmupDays": 30, "MakerFee": 0.00036, "TakerFee": 0.001, "UpdateData": true, "parameter_mining": []
name_comment — the name of the folder where the reports go: tester/report/first_test.
Set WarmupDays to no less than the strategy's longest indicator needs (for example, MA 200 on the
1h timeframe needs at least 9 days). Enter your own fees, taking your account tier into account. The other
parameters can be left at their defaults — they are described in the "Tester parameters" section.
Step 3. Run the test. There are two ways.
A) From the bot's web interface — the Tester tab. The bot keeps working in normal mode
meanwhile.
The Parameters tab — the tester status and the tester settings from the selected
tester/settings_strategy folder:
— Tester status — what is running now and its progress: a single test, parameter mining, a stress
test or a snapshot run, with start and finish times. Updates by itself;
— Settings folder — the path to the selected folder and its subfolders with the number of setting
files; click a folder to open it, .. goes one level up;
— Add setting — a new setting: exchange, pair, strategy and timeframe (no API keys needed, the
list of pairs is fetched from the exchange with a public request). Only exchanges the tester can download
history for are listed: Bybit, Binance (futures and spot), MEXC (spot and futures) and BitMEX. The pair can be
typed in by hand, several — comma-separated; a typed pair overrides the one selected in the list. This helps
when the pair list did not load (for example, the exchange is unavailable from your IP);
— in a setting's row: Test — test only this strategy, Edit,
Copy (a copy with a new name, exchange and pair — handy for replicating a setting to other pairs),
JSON — copy the setting to the clipboard, Delete;
— Edit config_tester.json — editor for the tester parameters (saves to the file);
— Download data — download historical data in advance for all tester settings for the period in
config_tester.json. The download status is shown separately, progress is in the bot console;
— Run tester — the "Tester wizard" window with the strategies of the selected folder: tick the
ones you need (or Select all).
After Test or Run tester the "Tester wizard" opens with an editor of the tester
parameters. Adjust the period, balance, etc. and choose what to run:
— Run — a single run of the ticked strategies on a shared balance with exact parameters, without
the parameter_mining sweep;
— Parameter mining — the full mode for the ticked strategies with the config from the editor: the
parameter_mining sweep, single_mode, parallel processes
(max_parallel_runs). Progress shows the number of completed combinations and the % of the current
run;
— Stress test — the same settings under worse conditions (see the "Robustness checks" section).
If the config in the editor differs from config_tester.json, the wizard asks before starting:
Save and run, Run without saving (the changes apply only to this run) or
Cancel. Only one parameter mining or stress test can run at a time.
Once started, the window closes and progress is shown in the Tester status block. When a single
test finishes, a Result button appears in the strategy's row — it opens the run's HTML report
right away.
The Results (files) tab — a file manager for the tester/runs,
tester/report and tester/data folders: sorting, open a report in the browser,
download or delete a file/folder (deleting is unavailable while a test or data download is running). A run
snapshot (run_snapshot_*.json) can be opened in the JSON editor, edited and started with the
Run button — the test is repeated with the settings from the snapshot. If a snapshot has many
strategies, their settings are not loaded into the editor right away so that the window opens quickly: the
Load strategy settings button opens them for editing, without it the snapshot runs with the
settings from the file as is. The + Mining parameter button also works in the snapshot editor.
B) From the console — handy for large sweeps. Run from the bot's folder:
# Windows manage_tester.bat menu: test, optimizer, download or convert data manage_tester.bat tester or hb_c.exe --run-tester manage_tester.bat download or hb_c.exe --download-data manage_tester.bat optimizer <folder> or hb_c.exe --run-report-optimizer tester\report\first_test # macOS ./run_tester_mac.sh or ./hb_c --run-tester # Linux ./hb_c --run-tester ./hb_c --download-data ./hb_c --run-report-optimizer tester/report/first_test
--run-tester — test, --download-data — only download data,
--run-report-optimizer — rebuild the summary optimizer report. On Windows all these modes are collected in
a single manage_tester.bat file (it replaced the former run_tester.bat, run_download_data.bat,
run_report_optimizer.bat and run_convert_data.bat): without arguments it shows a menu, and you can
drag a report folder onto the file to build the optimizer report for it. If the script is not in the bot's
folder, use the command from the right column.
In this mode the bot does not trade: it reads the settings, runs the tests and exits. If a trading bot is
already running on the same computer, run the tester from a separate copy of the folder.
Step 4. Watch the console (log). What matters in it:
— [LoadBars] ..., Загружено N баров для SYMBOL ("loaded N bars for SYMBOL") —
downloading and loading data. The first run on a new period may take a while, after that data is read from
disk;
— [RUN 1/1] start. params: ... — start of a run (in a sweep — with the run number and the
parameter values);
— Пропуск бота ... ("skipping bot ...") — the strategy is excluded from the test (no data, an
error in the settings), the reason is given in the line;
— [MINER] Обнаружены невалидные parameter_mining.name ("invalid parameter_mining.name found") — a
typo in the path of a swept parameter;
— at the end — BACKTEST REPORT with the totals and the line Interactive chart generated: ...
with the path to the HTML report.
Step 5. Study the results. Everything is in the tester/report/{name_comment} folder:
— the run's HTML report — open it in a browser (described in the "Report" section). Start with the header: PnL,
Max Drawdown, number of trades, Profit Factor. Then the equity curve, trades on the pair charts and the
Analytics tab — how much the result depends on a few lucky trades or a single pair;
— reports_history.csv — a row with the totals of each run (opens in Excel / Google Sheets);
— run_snapshot_{name_comment}_{date_time}.json — a full snapshot of the test settings. Each run
saves its own snapshot, earlier ones are not overwritten. You can run it
directly from the "Results (files)" tab (the Run button) or put it in tester/runs and repeat the
test from the console (the use_runs parameter).
The detailed run log (with use_logger = true) is in the logs folder, files
TESTER_*.log.
Step 6. Parameter tuning (optimizer).
1) Add the parameters to sweep to parameter_mining (examples in the "Optimizer" section).
Count the number of runs — it is the product of the number of values of all parameters;
2) download the data in advance: manage_tester.bat download or the Download data button;
3) for speed: max_parallel_runs — matching the number of CPU cores,
report.enable_html_report = false, use_logger = false; for millions of combinations —
monte_carlo;
4) start manage_tester.bat tester (or the Parameter mining button in the tester wizard) and check the console for
[MINER] warnings;
5) after the sweep, open report_optimizer_*.html and sort
reports_history.csv. Don't pick a single best run, pick a stable area where the neighboring values
are good too;
6) narrow the ranges around the best area and repeat. Check the final settings with a single test with an HTML
report on a different period that was not used for tuning.
Common problems.
- A strategy did not get into the test. The file is not in
tester/settings_strategy(the tester does not read the livesettings_strategyfolder), it is in a subfolder that is not selected in theSettings folderline (the console does not read subfolders), or it has a JSON error — the console will show[TESTER] failed to load settings file. Пропуск бота ...: нет данных("skipping bot ...: no data"). The pair was not traded on this exchange in the selected period,basic.symbolis misspelled, orUpdateData = falseandtester/datahas no files for that period.Market initialization failed. The instrument parameters could not be fetched: no connection to the exchange and no cache, or the exchange has no such pair.- The test ended before
EndDate. The console has a lineTester stopped: ...: the deposit is blown (Equity <= 0) ortarget_drawdown/target_drawdown_openwas reached. - No trades or very few. Not enough
WarmupDaysfor the indicators, the period is too short, or the lot is below the pair's minimum. A tester run is already in progress.. Parameter mining, a stress test and running a snapshot from the "Results (files)" tab can only run one at a time — wait for the current one to finish (the status updates automatically).Compiled executable not found. Therun_*.batscript was not started from the bot's folder.
Market data for
testing
Crypto exchanges publicly share historical market data. The tester downloads the needed data range itself,
builds 1-minute candles from it, and then builds bars of the required timeframe for the bot from those
minutes. No manual steps or registration required.
In addition, WarmupDays days before the test start are downloaded, so all of the strategy's TA
indicators are calculated by StartDate.
Supported exchanges. The exchange is taken from the strategy settings file: settings.exchange.name.
- BYBIT — futures (
bybit) and spot (bybit-spot). Archives of all trades frompublic.bybit.com. - BINANCE — USDT-M futures (
binance,binance-papi) and spot (binance-spot). Daily archives of aggregated trades fromdata.binance.vision. - MEXC — spot (
mexc) and futures (mexc-futures). Ready-made 1-minute candles via the exchange's public API. - BITMEX — (
bitmex). Daily trade archives frompublic.bitmex.com. One file contains trades for all pairs at once — the tester downloads it once and splits it into per-pair folders.
If an exchange without a downloader is specified, the tester uses BYBIT data.
Storage. Data is saved in the
folder tester/data/{exchange}/{symbol} — one file of 1-minute candles per day
in Parquet format (2026-02-03_1m.parquet). The files are compressed and
take less space than CSV. Downloaded trade archives are deleted after conversion to save space.
Days that were already downloaded are not downloaded again: on subsequent tests the tester only fetches the
missing days (if UpdateData = true). With UpdateData = false the test runs only on the
data already in the folder.
When a test starts, only the daily files for the test period (including warm-up) are read, so years of
accumulated history don't slow down short tests. Files without a date in the name are not read.
During a parallel sweep the processes don't interfere with each other: only one process downloads a given
pair at a time, the others wait and use the finished files.
Data in the old CSV format. Data downloaded by earlier bot versions (*_1m.csv) doesn't
need to be downloaded again: on the first test of a pair the tester converts its CSV files to Parquet and
deletes the CSV. To convert the whole tester/data folder at once, use manage_tester.bat convert
(on macOS, run_convert_data_mac.sh) in the bot's folder: it runs the bot with the
--convert-data flag. It can also be run while the tester is working.
Your own data. You can drop your own data in the tester/data/{exchange}/{symbol} folder in
CSV format. On the first test of that pair (or via manage_tester.bat convert) the tester
converts it to Parquet and deletes the original CSV, so keep a copy if you need it. Requirements:
— one file per day, the name ends with the date and _1m.csv, e.g. 2026-02-03_1m.csv
(files without a date in the name are not read);
— 1-minute candles (the tester walks through history in 1-minute steps / optionally it can run on every tick, but that is slow);
— the first line is a header, followed by the columns timestamp,open,high,low,close,volume (other
columns are ignored; if there are 9 or more columns, columns 7–9 are read as
buy_volume,sell_volume,trades);
— timestamp in UTC: unix time in seconds, milliseconds, microseconds or nanoseconds (the format is
detected automatically), or a date string 2026-02-03 00:01:00;
— columns are separated by commas, the decimal separator is a dot.
Example:
timestamp,open,high,low,close,volume 1770076800000,97512.5,97540.0,97480.1,97530.2,12.345 1770076860000,97530.2,97561.7,97522.0,97555.0,8.910
Pre-downloading. The manage_tester.bat download command (item 3 in the menu) runs the bot with the
--download-data flag. In this mode the tester doesn't test anything, it only downloads all the
data needed for the test period (+ warm-up) for all pairs from tester/settings_strategy, including the
pairs from the parameter_mining sweep. Handy to run in advance before a large sweep.
Tester
behavior
From the bot's point of view, the tester is just another exchange. The bot connects to it and starts receiving bars, placing orders, etc. Meanwhile the tester simply emulates the behavior of a real exchange.
Time and candles. The tester walks through history in 1-minute steps, synchronously across all trading pairs.
From the minutes it builds candles of the strategy's working timeframe (1m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d,
1w) aligned to UTC, just like on the exchange: 1h candles start at XX:00, 4h — at 00:00/04:00/08:00…, 1d — at 00:00 UTC,
1w — on Monday 00:00 UTC.
The strategy is called every minute, not only at candle close — for the 1h timeframe that's ~60 calls
per candle. The bot receives closed bars and the current forming candle, whose OHLC is updated every
minute. So logic that depends on the price inside a candle (trailing stops, moving orders, exiting at the
current price, etc.) works the same as in live trading.
Bars of the warm-up period (WarmupDays) are only used to calculate indicators — trading
starts at StartDate. If a minute is missing from the data (no trades), the tester inserts an
"empty" candle at the last price.
Order execution. On each 1-minute candle the tester checks all pending orders against its High/Low. The price path inside the minute is modeled: for a rising candle Open → Low → High → Close, for a falling one Open → High → Low → Close. Orders are filled in the order the price reaches them along this path, not in the order they were placed. For example, if both a stop and a take profit are hit within the same minute, the one the price reached first is filled, and the second one (reduceOnly) is cancelled because the position no longer exists.
market— filled immediately at the current price with slippage (SlippagePercent): buys fill higher, sells fill lower. Taker fee. Withorder_market_delay = true— at the open price of the next minute.limit— filled at its own price once the minute's price reaches it (Low ≤ price for a buy, High ≥ price for a sell). Maker fee. WithLimitOrderVolumeCheck = truethe filled amount is limited by the volume of the 1-minute candle — partial fills are possible, the remainder waits for the next candles. Withorder_limit_fill_plus_tick = truea mere touch is not enough: the price has to go through the limit level.stop/stop_market— triggers when the trigger price is touched and is filled at that price with slippage. Taker fee. Withorder_trigger_fill_worst = truegaps are taken into account: if the minute already opened beyond the trigger, the stop is filled at the minute's open price (as on a real exchange during a sharp move).stop_limit— activated by the trigger and filled at the limit price if it is also reached within that minute. Maker fee.take_profit— filled at the trigger price when it is reached. Taker fee.
Orders can be modified (price, size, trigger) and cancelled — just like on the exchange.
reduceOnly is supported: such an order can only reduce a position and will never flip it. The
strategy's use_long/use_short settings are respected: if a direction is disabled, an
order in that direction can only close the opposite position, and the "excess" size is cut off.
Positions. One-Way mode (one position per pair): a buy while short first closes/reduces the short, and
the excess opens a long (a flip). When adding to a position, the entry price is averaged. PnL is realized on
every close or reduction of a position.
Spot. The tester takes the market type from the exchange's instrument parameters. There are no shorts
on spot: a sell can only reduce or close a long, the "excess" size is cut off. No funding is applied on spot.
Balance is shared across all strategies. Behaves like BYBIT/BINANCE futures with cross margin. The bot
can request the Wallet or Margin balance:
— Wallet — realized balance: initial balance + realized PnL − fees ± funding;
— Margin (equity) — Wallet + unrealized PnL of all open positions. The equity curve and the
maximum drawdown are based on it.
The fee is deducted from the balance immediately on every order fill.
If the Margin balance drops to zero, the tester stops the run — the deposit is "blown", there is no point
testing further. Liquidation of individual positions is not modeled: the test continues even through a deep
drawdown, so you can see how the system behaves after it. To stop the test earlier, use the
target_drawdown_open and target_drawdown parameters.
Funding. Every FundingIntervalHours hours (UTC, at the start of the hour) funding is
applied to all open futures positions: position size × price × FundingRate. With a positive rate,
longs pay and shorts receive. The totals are shown in the report (Funding paid / received / net). To disable
funding, set FundingRate = 0.
Bot logic. The tester runs the very same logic as live trading: the position service, the limiter of simultaneously open positions, account options (e.g. closing on margin profit) — all of this is the bot's shared production code.
Report
Once testing is finished, a detailed interactive HTML report is saved to the
folder tester/report/{name_comment}.
And a record is added to reports_history.csv with summary information about the test, for easily
finding the best parameter combinations when optimizing strategies.
Optimizer report. When sweeping parameters (parameter_mining), in addition to the report for
each run, the tester builds one more, summary report report_optimizer_*.html across all runs at once.
It shows the sweep results as heatmaps and 3D surface charts: the X and Y axes are the values of the swept
parameters, the Z axis is the metrics (return, drawdown, Profit Factor, etc.). This way you immediately see
stable "plateaus" of good values rather than isolated random peaks. The report is created automatically during a parallel
sweep (max_parallel_runs > 1) or manually via manage_tester.bat optimizer,
see the "Optimizer" section for details.
Almost every metric, column and chart in the reports has a tooltip: hover over the name to see what the figure means and how it is calculated.
Report header — key metrics:
Pairs- number of trading pairs (strategies) in the testInitial Balance/Final Balance- starting and ending balance in USDTTotal PnL- total profit/loss in USDT and %Total Trades (Win/Los)- number of full trades (from opening a position to closing it completely), of which profitable and losing after feesWin Rate- percentage of profitable full tradesMax Drawdown, %- maximum drawdown of the Margin balance from its peak in % (its size in USDT in parentheses)Max Drawdown, USDT- maximum drawdown in money (its % of the peak in parentheses). These are two independent values: with a growing deposit the largest drawdown in money is usually a late one and smaller in %, while the largest in % is an early one. For example, 4509 USDT (9.83%) at a peak of 45869 and 1885 USDT (20.42%) at a peak of 9234Max Unrealized Drawdown, %- maximum unrealized loss of open positions as % of the Wallet balance at the same moment:(Wallet − Margin) / Wallet(the loss in USDT in parentheses). This is the lowest point of theUnrealized Drawdown/Profit %line on the balance chart; unrealized profit is not counted. It is the same valuetarget_drawdown_openstops the test on. In a portfolio it can be larger thanMax Drawdown, %: while one pair accumulates a loss, others take profit, Wallet grows, and Margin barely drops from its peakTotal Fees- total fees paidPosition avg (max), %- average (and maximum) total size of open positions as % of the Margin balance. Shows how heavily the system loads the depositProfit Factor- ratio of gross profit to gross lossDuration (days)- length of the test period in days
Charts:
Equity Curve- chart of the Margin balance (accounting for all open positions and unrealized PnL) and the Wallet balance. TheLiquidation Levelline (toggle it in the legend) is the cross-margin liquidation level, roughly as in Bybit UTA: the total maintenance margin of open futures positions in USDT (notional × risk-limit tier MMR − mmDeduction + taker fee to close). If the Margin balance falls below this line, a real exchange would liquidate the positions. For Bybit the risk-limit tiers are downloaded from the exchange; for other exchangesmaintenance_margin_ratefromconfig_tester.jsonis used. Chart only, it does not stop the test. When there are no open positions, the line has gapsMonthly Returns Heatmap- heatmap of returns by month and the total for each yearOpen Positions Size- total size of open positions in USDT: overall, longs and shorts separately, and split by trend and counter-trend strategiesStrategy Charts- separate candlestick charts for each strategy with trade markers and the strategy's TA visualizationRealized PnL by Symbol- cumulative realized PnL for each pair and in total. Pairs are toggled in the legend, theSelect all/Deselect allbuttons show or hide all of them at once
Report Statistics — detailed statistics:
- Period & Scope (test period)
Report range- test start and end datesDays in test- number of days in the testMonths in test- number of calendar months the test coversMonths with data- number of months for which the return was calculatedPairs count- number of pairs (strategies)
- Balance & Equity (balance)
Initial balance/Final balance- starting and ending balanceMin balance/Max balance- minimum and maximum Margin balance over the whole test
- Monthly Performance (monthly returns)
Average monthly return (geometric), %- average monthly return with compounding (reinvestment). The most honest estimate of "how much per month on average"Average monthly return (arithmetic), %- simple arithmetic mean of monthly returnsBest month, %/Worst month, %- best and worst month
- PnL, Volume & Fees (profit, volume and fees)
Total PnL/Total PnL, %- total profit/loss in USDT and %Gross profit- sum of all profitable closes (gross profit)Gross loss- absolute sum of all losing closes (gross loss)Trading volume (USDT)- total trading turnoverTotal transactions (buy/sell)- total number of order fills (buys and sells)Total fees- total fees paidFunding net- net funding (received minus paid)Funding accrued (received)- how much funding was receivedFunding paid- how much funding was paidPnL without top 5 winning trades- Total PnL without the 5 most profitable trades. If the result turns negative, the profit rests on a few lucky outliersPnL without best pair- Total PnL without the contribution of the most profitable pair (n/a with a single pair). Shows whether the portfolio works or a single pair carries everything
- Trades (trades). A trade is a full trade: from opening a position to closing it completely or
flipping it. Averaging and partial closes within one position belong to the same trade. The trade result
is calculated net of fees.
Total Trades/Win Trades/Los Trades- total, profitable and losing tradesWin Rate, %- percentage of profitable tradesExpectancy per trade- expectancy: the average result of one trade in USDT net of feesAvg win/Avg loss- average winning and losing tradePayoff ratio- average winning trade / average losing trade (based on full trades, unlikeRisk/Reward, which is based on fills)Expected Value- expected result of a trade:WinRate × Avg win − LossRate × |Avg loss|. LossRate is the share of losing trades among all trades (breakeven trades are not counted as losing). A value above 0 means the system has an edgeLargest win/Largest loss- the most profitable and the most losing tradeAvg fills per trade- how many fills there are per trade on average (1 entry + 1 exit = 2; more means averaging and partial take profits)Avg holding time/Max holding time- average and maximum position holding timeMax consecutive wins/Max consecutive losses- longest streak of profitable and losing trades in a row
- Fills (fills that reduced or closed a position — each partial take profit separately, PnL before
fees)
Fills/Win Fills/Los Fills- number of such fills, profitable and losingFill Win Rate, %- percentage of profitable fillsExpectancy per fill- average result of one fill before feesMax consecutive win / loss fills- longest streak of profitable and losing fills in a row
- Risk & Exposure (risk and deposit load)
Position avg / max, % of margin balance- average and maximum total size of open positions as % of the Margin balanceLong / Short Position avg / max, % of margin balance- the same, separately for longs and shortsMax Drawdown, %/Max Drawdown, % — amount- maximum drawdown in % and its size in USDTMax Drawdown, USDT/Max Drawdown, USDT — %- maximum drawdown in USDT and its % of the peakMax Unrealized Drawdown, % of wallet/— amount/— time (UTC)- maximum unrealized loss as % of Wallet, in USDT, and the moment it happened
- Risk by strategy (deposit load by strategy type)
T ...- average and maximum position size (overall, long, short) of trend strategies as % of the Margin balanceCT ...- the same for counter-trend strategies
- Benchmark (Buy & Hold) (comparison with simply buying and holding the same pairs)
Strategy return, %- the strategy's return over the test periodBuy & Hold return (equal weight), %- the return if the initial balance had been used at the start of the test to buy all pairs of the portfolio in equal shares and hold them to the endExcess return vs Buy & Hold, %- how much better (or worse) the strategy is than simply holdingStrategy Max Drawdown, %/Buy & Hold Max Drawdown (daily), %- maximum drawdown of the strategy and of the Buy & Hold portfolio (by daily closes)
- Risk-Adjusted Ratios (return/risk ratios)
Profit Factor- gross profit / gross loss. Above 1 means the system is profitableRisk/Reward- average winning trade / average losing tradeRecovery Factor- Total PnL / Max Drawdown, USDT. How many times the profit covers the maximum drawdownSharpe ratio (monthly)- Sharpe ratio based on monthly returns (annualized). Return relative to overall volatilitySortino ratio (monthly)- Sortino ratio. Like Sharpe, but only takes downside volatility (drops) into accountCAGR, %- compound annual growth rate of capitalCalmar ratio- CAGR / Max Drawdown %. Annual return relative to the maximum drawdownUlcer Index (hourly), %- square root of the mean squared drawdown from the peak, based on hourly values of the Margin balance. Unlike Max Drawdown, it takes into account both the depth and the duration of all drawdowns: a long time "under water" increases the indexMartin ratio- CAGR / Ulcer Index. Return relative to how "painful" the drawdowns are
Details — detail tabs:
Settings- settings of all strategies that took part in the testTrades- tables with all trades for each pair: time, order, strategy, side, action, size, price, fee, PnL, balance, position after the trade, position value in USDT and as % of the Margin balance. TheTrade Max DD (incl. unrealized)column, for fills that closed or reversed a trade, is the deepest drawdown of the whole trade with unrealized loss included (MAE) in USDT, in brackets — as % of the Margin balance when the trade was opened. 0 — the trade never went below zeroMarkets- instrument parameters: instrument type (Type: on Bybitcrypto,stock,ETF,commodity,forex, etc.), maximum market order size, maximum leverage, lot step, current price and average daily trading volume over 1, 10 and 100 daysSummary- summary table for each pair: number of full trades, Win Rate, Profit Factor, PnL, Buy & Hold return of that pair over the test period, fees, trading volume, average and maximum position size in %, the best and worst trade (Best Trade/Worst Trade, net of fees) andMax DD (incl. unrealized)— the max drawdown of the pair's result with unrealized loss included: from the peak of the cumulative PnL of closed trades to the deepest point of a later tradeCorrelation- correlation matrix of the pairs' daily PnL (realized + unrealized). High positive correlation (red) means the pairs lose at the same time and there is no diversification. Negative (green) means the pairs hedge each other. The portfolio's average pairwise correlation is also shown. With many pairs, the 25 pairs with the largest |PnL| are shownDrawdown- breakdown of the maximum drawdown in % (Max Drawdown, %) by pair: the moment of the peak and the trough of the Margin balance and how much each pair's contribution changed (realized and unrealized PnL, fees, funding) over that period. The contributions add up to the size of this drawdown in USDT. You can see which pairs "made" the drawdown and which ones softened it at that moment (negative share)Analytics- extended analytics: how robust the result is and where it is earned. Turned off with thereport.include_analyticsparameter- Robustness (is the result real or overfitted)
Dependence on outliers- PnL of the 5 best trades, their share of Total PnL, PnL without them; the best pair and PnL without itMonte Carlo(enabled byreport.analytics_monte_carlo). Works with the sequence of closed trades (PnL net of fees, without unrealized PnL — so the drawdown here is usually smaller than the report's Max Drawdown). Two methods:
shuffling — the same trades in random order. The total doesn't change, the path does. Shows the 5/50/95 percentiles of the maximum drawdown and the share of permutations with a drawdown deeper than the actual one. If that share is 80% or more, the actual order of trades was a lucky one, and in live trading you should expect a deeper drawdown;
bootstrap — trades are drawn at random with replacement. Shows the 5/50/95 percentiles of the final PnL and drawdown, the probability of a loss and the probability of the balance going to zero.
Both methods show histograms with the actual value marked. At least 5 trades are needed
- Drawdowns (drawdowns)
- number of drawdown episodes, the longest drawdown (from the peak back to the peak), % of time under
water,
Ulcer Index,Martin ratio - table of the top 5 drawdowns: start (peak), trough, recovery date (or
not recovered), depth in USDT and %, time to fall, time to recover and total duration. Duration and recovery time often matter more than depth
- number of drawdown episodes, the longest drawdown (from the peak back to the peak), % of time under
water,
- Trade quality (quality of full trades)
Avg win/Avg loss,Payoff ratio,Expected Value(WR × avg win − LR × |avg loss|), the largest win and loss with pair and dateMAE / MFE- the worst and best intermediate PnL of each trade (realized − fees + unrealized by the Low/High of 1-minute candles). Average MAE of all trades and of winning ones, worst MAE, average MFE, the share of profit winning trades captured from their maximum, how many losing trades were in profit at some point. Scatter plots MAE → result and MFE → result: a deep MAE on winning trades means the stop can't be placed closer; points far below the PnL = MFE line mean profit is given back, the take profit is too far or the exit is too late- the
Long / Short / Alltable: number of trades, Win Rate, Profit Factor, PnL, average trade and average holding time separately by side - histogram of the trade PnL distribution
- When and in which conditions (when and under which conditions it earns)
- heatmap of PnL by hour of day (UTC) and day of week — change of the Margin balance per hour, with totals by day and by hour
- rolling 30-day chart: return, % and Sharpe ratio (annualized, based on daily returns). A decline toward the end of the test means the strategy is "running out of steam". Needs more than 30 days of data
- PnL by market regime. Each pair's daily PnL is assigned to the regime of its market on that day: Trend — Kaufman's efficiency ratio over 14 days ≥ 0.3, otherwise Flat; High vol — ATR(14) as % of price not below this pair's median for the period, otherwise Low vol. For each of the 4 combinations and the totals by a single criterion: pair-days, PnL, average PnL per pair-day, % of profitable days, share of PnL
- Risk and costs (risk and costs)
Distance to liquidation- the minimum distance to liquidation during the test, when it happened, and the 5 closest days. Calculated as Margin balance / total notional of open positions: by how many % all positions would have to move against you at once to wipe out the balance. Maintenance margin is not taken into account here, so a real exchange liquidates earlier; theLiquidation Levelline on the balance chart shows the liquidation level with it- daily
VaR 95%(historical: the loss exceeded on 5% of days) andCVaR 95%(the average loss on those worst 5% of days), the worst and best day, skewness and kurtosis ("fat tails") of daily returns. VaR/CVaR need at least 20 days of data Costs- gross profit, fees and funding paid as % of gross profit, net costs (fees − net funding), PnL before costs. Shows how much costs "eat"
- Robustness (is the result real or overfitted)
Frequency- how often orders are filled: charts of fills by day and by month; a summary — total fills (opens / closes / flips), days with fills, average and median per day, the most active and the quietest month, the longest period without fills; tables by month and by pairTester Config- tester parameters and the values of the swept parameters for this run, plus the account optionsclose_by_margin,open_positions_limiterandrisk_multiplier
Tester
parameters
file: config_tester.json You can edit the file in a text editor.
name_comment - a comment for the test. To make it easier to navigate reports. Reports are
saved to a separate folder tester/report/{name_comment}.
comment - a free-form run comment that helps tell reports in one folder apart. It is shown in the
report header and on the compare runs page. On start the folder the strategy settings were taken from is
appended to it automatically: [settings: settings_strategy/…]; this mark is not saved to
config_tester.json.
InitialBalance - the starting balance for testing, in USDT
StartDate - the test start date in the format 2026-02-03T00:00:00
EndDate - the test end date in the format 2026-02-13T00:00:00
WarmupDays - number of days to warm up before testing begins. Data for these days is
downloaded in addition, before StartDate, so the TA indicators are calculated by the start of
testing. If there is less data before StartDate than WarmupDays (e.g. the pair was listed on
the exchange later), trading on this pair starts later, once the full warm-up is available. The console will
show a line with the new start date.
MakerFee - maker fee (0.0001 = 0.01%) Standard on BYBIT: 0.00036 = 0.0360%.
(a guide on how to significantly reduce fees)
TakerFee - taker fee (0.0001 = 0.01%) Standard on BYBIT: 0.001 = 0.1000%
SlippagePercent - slippage for market orders (0.0001 = 0.01%)
LimitOrderVolumeCheck - volume check for correct execution of limit orders (true/false).
A limit order is filled no more than the volume of the current candle allows: the tester "bites off" the available
volume from the order, and the remainder waits for the next candle (partial/step-by-step fill). If off — the limit order is filled in full
when the price is touched.
order_trigger_fill_worst - realistic fills of stop orders on gaps (true/false). By default
a stop is filled at the trigger price (± slippage). If on, the stop is filled at the worse of the two prices:
the trigger or the open price of the 1-minute candle. For example, a sell stop at 100 and the minute opened at 97 — the fill
is at 97, not 100. Makes the test more conservative on sharp moves and on low-liquidity pairs.
order_limit_fill_plus_tick - realistic fills of limit orders taking the order book queue into account
(true/false). By default a limit order is filled when the price touches it. On a real exchange, when the price touches the level, the order
often isn't filled — other orders are ahead of it in the queue. If on, a limit order is filled only when
the price has gone through its level. For example, a buy limit at 95 is filled only if the minute's Low is below 95 —
a touch of exactly 95 doesn't count. Especially important for grid and averaging strategies.
order_market_delay - delayed execution of market orders (true/false). By default a market order
is filled instantly — at the close price of the same minute the strategy just saw. On a real
exchange, time passes between the bot's decision and the fill, and the price has time to move. If on, a market order
is filled at the open price of the next minute (+ slippage). In this case the bot sees the position
only on the next step, as on the exchange. Closing positions at the end of the test always happens immediately.
target_drawdown_open - target drawdown on open positions in % (0 = off). Calculated as
the gap between the Margin balance and the Wallet balance, i.e. the current unrealized loss of open positions:
(Wallet − Margin) / Wallet × 100. As soon as it reaches the set level, the test ends
(e.g. 50 stops when Margin has dropped 50% below Wallet). You can use it as your own
"liquidation" level — to cut off runs you would not survive on a real account.
target_drawdown - target maximum drawdown in % (0 = off). Calculated the same way as
Max Drawdown, % in the report: the drop of the Margin balance from its historical maximum (high watermark),
(Peak Margin − Margin) / Peak Margin × 100. It includes losses already realized, not only
open positions. As soon as it reaches the set level, the test ends.
Example of the difference: balance 100, a long is opened, Margin grows to 150 and then falls to 90. target_drawdown_open
sees 10% (Margin is 10 below Wallet 100), while target_drawdown sees 40% (from the peak of 150).
When the test is stopped by either parameter, open positions are closed at the current price and the report is built on the data up to
the moment of the stop. Handy for parameter sweeps: obviously bad runs are cut short and don't waste
time.
FundingRate - Funding rate size (0.0001 = 0.01%)
FundingIntervalHours - Interval between funding payments in hours (8)
maintenance_margin_rate - maintenance margin rate as a share of position notional (default
0.005 = 0.5%). Used for the Liquidation Level line on the balance chart when the exchange
provides no risk-limit tiers (currently tiers are downloaded only from Bybit). Does not affect the test itself.
accounts - the tester account. The first item of the list is used: close_by_margin and
open_positions_limiter for all strategies in the test come from it. No API keys needed.
If the section is missing, a default account is created (options off):
"accounts": [ { "name": "tester", "open_positions_limiter": 0, "close_by_margin": { "profit": 1.0,
"loss": 1.0, "size": 1.0, "each": false } } ]
open_positions_limiter - maximum number of simultaneously open positions for the HiDeep,
RedFlag, SmartProfit and ShadowOverlap strategies (0 — no limit)
close_by_margin.profit - when Margin ≥ Wallet × profit, the positions of all strategies
are reduced by the size fraction (1.04 — Margin is 4% above Wallet; 1 — off).
each: on — Margin is calculated as Wallet + unrealized PnL of the bot's positions, off — the whole
account's Margin balance
UpdateData - update (download missing) market data before testing (true/false)
use_logger - whether to use the logger. If off, testing runs faster (true/false)
max_parallel_runs - number of parallel tester runs when sweeping parameters. Each run is started
as a separate process. If the computer's performance allows it, processes can be parallelized without losing
calculation speed. With a value greater than 1, the summary optimizer report (heatmaps / 3D surface) is built
automatically after all runs finish.
max_memory_load_percent - RAM load threshold in % for parallel runs (default
97). If memory is loaded up to this level (including the memory a new run will take — estimated from the
average peak of the runs that have already finished), new
runs wait until it frees up. Runs that crashed due to lack of memory are retried automatically. 0 — no
control.
single_mode - separate testing mode (true/false). If on, each settings file from the
tester/settings_strategy folder is tested separately rather than all together on a shared balance. Handy
for evaluating each strategy/pair separately in a single launch. The parameter_mining sweep is applied to
each strategy.
use_runs - run tests from saved snapshots (true/false). If on, the tester ignores the current
settings and runs all *.json files from the tester/runs folder one after another. Each
file is a full snapshot (strategies, program settings and tester settings, including the tester account in
accounts). This mode works only when launched from the console (--run-tester): the
Parameter mining button ignores it, and a single snapshot is run in the web interface with the
Run button on the "Results (files)" tab. The tester saves such snapshots,
run_snapshot_{name_comment}_{date_time}.json, to the report folder itself before every run (both
for a parallel and a sequential sweep) — you can copy
them to tester/runs to repeat them or queue several different
tests.
shuffle_miner, monte_carlo, monte_carlo_seed - additional optimizer
modes, described in the "Optimizer" section.
file: config_tester.json/report Report content settings:
enable_html_report - create the HTML report (true/false). If off — no HTML is generated, only a
row with summary metrics is added to reports_history.csv. Greatly speeds up large parameter
sweeps and saves disk space.
chart_ohlc_height - OHLC chart height in pixels
chart_balance_height - balance chart height in pixels
chart_position_height - open position size chart height in pixels
include_chart_ohlc - include the OHLC chart in the report (true/false)
include_chart_balance - include the balance chart in the report (true/false)
include_chart_position - include the open position size chart in the report (true/false)
include_settings - include strategy settings and tester parameters in the report (true/false)
include_trades_table - include tables listing trades for each strategy (true/false)
include_summary_table - include the summary table for all strategies: trading volume, fees,
etc. (true/false)
include_monthly_returns_heatmap - include the monthly returns heatmap (true/false)
include_position_stats - include open position statistics: average and maximum size of
open positions as % of the Margin balance (true/false)
include_analytics - include the Analytics tab (true/false, default
true)
analytics_monte_carlo - number of Monte Carlo iterations over trades on the Analytics tab
(0 = off, 1000 recommended). Not to be confused with the optimizer's monte_carlo, which limits
the number of sweep runs. Calculation time grows in proportion to iterations × number of trades and is spent in every
run, including during a sweep: 1000 iterations on 100 trades take a fraction of a second, 10000 iterations on thousands of trades take
noticeably longer
analytics_monte_carlo_seed - seed of the random number generator for the report's Monte Carlo
(default 42). With the same seed the result is repeated
enable_timing_logs - print to the console the generation time of each report stage. Useful for
diagnostics if reports take a long time to build (true/false)
file: config_tester.json/reports_history Additional columns of
reports_history.csv:
The main columns are always written. The additional ones are off by default and are enabled one by one (true/false).
Enabled columns can be used in the optimizer's z_parameters, for example to look for
parameters that are robust to outliers.
pnl_without_top5 - the PnLWithoutTop5 column: Total PnL without the 5 most profitable
trades
pnl_without_best_pair - the PnLWithoutBestPair column: Total PnL without the most profitable
pair (empty with a single pair)
ulcer_index - the UlcerIndex column: Ulcer Index based on hourly values of the Margin balance, %
mc_max_dd_p95 - the MC_MaxDD_p95 column: 95th percentile of the maximum drawdown from the
bootstrap, % (requires report.analytics_monte_carlo > 0, otherwise empty)
mc_loss_probability - the MC_LossProbability column: probability of a loss from the bootstrap, %
(requires report.analytics_monte_carlo > 0, otherwise empty)
Example:
"reports_history": { "pnl_without_top5": true, "ulcer_index": true }
Robustness checks and report
publishing
Walk-forward. Set walk_forward.oos_percent in config_tester.json (for example
30) and the last part of the period is kept out of optimization. The sweep runs on the first part,
then the best top_n combinations by metric (default TotalPnLPercent) are
re-run on the held-out part in the {name_comment}_WF_OOS folder. The result is the
walk_forward_*.html report: optimization vs. check results, return per 30 days, WFE and a verdict.
oos_percent = 0 turns it off.
Parameter plateau. report_optimizer_*.html now has a robustness section: for the best
combinations it shows the average over neighboring parameter values and the worst neighbor. When the best result
is an isolated peak and its neighbors are much worse, the report marks it as fragile: such settings are most likely overfitted.
Stress test. The Stress test button in the tester wizard (or --run-stress-test from
the console) runs the ticked strategies with the config from the editor in several scenarios: fees x2, slippage x3, funding x3,
market order delay, stops at the worst price, strict limit fills and all of them combined. The stress_test_*.html report is saved in
{name_comment}_STRESS and shows how much the strategy loses in each scenario.
Compare runs. On the "Results (files)" tab tick two or more HTML reports and press Compare selected: return
curves on one chart (each can be hidden in the legend) and the key metrics side by side, with the difference relative to
the first run and the best value highlighted. Reports can be ticked in different folders: the selection is kept
while you move between folders, a counter shows how many are ticked, Clear selection resets it. For
each run the compare page shows the report creation time and the comment. Works for reports created by this bot version or newer.
Market regimes. The Analytics tab splits the result into uptrend, downtrend, range and high/low
volatility, with a summary line of where the strategy earns and where it loses.
Telegram notification. When a long run started from the web interface finishes (sweep, snapshot,
stress test), the bot posts to its Telegram chat: duration, number of runs, best result and the summary
reports created. Turn it off with notify_telegram = false.
Publishing a report. Each report folder on the "Results (files)" tab has a Publish button. In the
form the strategy description and contact are optional, you only need to confirm the agreement; you can tick which
files of the folder to send. The archive is built and sent in the background, the window closes right away, and
you are notified of the result. The bot sends an archive to the hamster-bot tester reports Telegram chat:
reports_history.csv, the settings snapshot, the summary reports and the HTML of the best runs. API keys, tokens and
the license are removed before sending.
Optimizer
(parameter sweep)
The optimizer automatically runs the test many times, each time with a new combination of values of the
selected parameters. The result of each run is written as a separate row to the summary table
tester/report/{name_comment}/reports_history.csv: the test metrics plus columns with the values of
the swept parameters. Sorting it makes it easy to find the best combinations.
file: config_tester.json/parameter_mining Optimizer (parameter sweep)
settings:
By default this is an empty list [] — a regular single test. The list is filled with objects like
{"name": "parameter_name", "start": 1, "end": 10, "step": 0.5, "values": []}. Each object is one
swept parameter.
Sweep wizard. You don't have to write the path by hand: in the web interface, above the
config_tester.json editor, there is a + Mining parameter button. The wizard asks step by step what
to sweep (strategy settings or the tester itself), which strategies to apply it to (* — all of them),
lets you find the parameter in the tree by searching (e.g. take_profit) and set the range
start/end/step or a list of values. You immediately see how many
values and how many combinations in total you will get. If the parameter is already in parameter_mining, the wizard
offers to replace it. Don't forget to save the config after adding.
name - path to the parameter to sweep. You can specify any bot setting. The path starts with
one of 4 kinds of config:
1) settings — strategy settings (.json files in the tester/settings_strategy folder). Here
we configure: the trading pair, the timeframe, deposit handling, and which strategy runs with which
settings.
Example: settings[*].mrs2.ma_long.type - sweeps the type parameter of the opening order
for the mrs2 strategy
2) account — the tester account (the accounts section in config_tester.json).
Here we configure the account-wide take profit by margin balance or the limit on the number of simultaneously
open positions.
Example: account[*].close_by_margin.profit - sweeps the profit parameter of the
close_by_margin option
3) settings_program — general bot program settings (the
settings_program.json file). Here we configure the overall lot size multiplier risk_multiplier.
Example: settings_program.risk_multiplier
4) config_tester — settings of the tester itself (the config_tester.json file). For example,
you can run tests with different fee or slippage levels.
Example: config_tester.MakerFee
Selecting a specific strategy/account. Square brackets specify which files to apply the
parameter to:
settings[*] — to all settings files at once
settings[0] — only to the first file (numbering starts at 0, in load order)
settings[my_set_btc] — only to the file whose name field equals
my_set_btc
The same works for account[...] and for nested lists inside the settings (e.g.
[*], [0] on a list of orders).
start - starting value of the parameter
end - ending value of the parameter (inclusive). You can also sweep in descending order if
start > end
step - step size for the parameter
values - an explicit list of values to sweep. If the list is not empty,
start/end/step are ignored. Values are written as strings and are
automatically converted to the parameter's type: text, numbers ("5", "10", "25"), true/false
(["true", "false"]) and option lists (enum).
For example, for the moving average type the available values are:
["SMA", "EMA", "GMA", "HARMONIC", "TEMA", "DEMA", "ZLEMA", "WMA", "VWMA", "RMA", "EHMA", "THMA", "HMA", "DMA", "ATR", "H", "L", "SMA_KALMAN", "EMA_KALMAN", "GMA_KALMAN", "HARMONIC_KALMAN", "TEMA_KALMAN", "DEMA_KALMAN", "ZLEMA_KALMAN", "WMA_KALMAN", "VWMA_KALMAN", "RMA_KALMAN", "EHMA_KALMAN", "THMA_KALMAN", "HMA_KALMAN", "DMA_KALMAN", "ATR_KALMAN", "H_KALMAN", "L_KALMAN"]
For the price source:
["open", "high", "low", "close", "hl2", "hlc3", "ohlc4", "hlcc4", "oc2"].
For sweeping a list of trading pairs - see Example 1.
Name validation. Before starting, the tester checks every name. If no parameter with that path is
found (a typo, no such strategy, etc.), a warning is printed to the console:
[MINER] Обнаружены невалидные parameter_mining.name ("invalid parameter_mining.name found"), and that parameter is not applied — the tests
will run with the original value. Always check the console on the first run of a sweep.
Number of runs is the product of the number of values of all parameters. If you set two parameters
to sweep, for example from 1 to 10 with a step of 1, 100! runs will be performed (10 variants of the first
parameter × 10 variants of the second parameter). The results of all tests are saved as separate html reports and
in the reports_history.csv summary table.
Tips for a large sweep:
— turn off HTML reports (report.enable_html_report = false) and the logger
(use_logger = false) — this greatly speeds up runs and saves disk space;
— increase max_parallel_runs to match the number of CPU cores;
— if there are too many combinations, use monte_carlo (see below).
Additional sweep modes (file: config_tester.json):
single_mode - each settings file from tester/settings_strategy is tested separately, and the whole
parameter_mining sweep is run for each of them. For example, 5 settings files × 20 combinations
= 100 runs. Handy when you need to tune parameters for each pair independently rather than for the portfolio.
shuffle_miner - sweeping trading pairs without repeats across strategies (true/false). Works when the
tester/settings_strategy folder has several settings files and parameter_mining has a parameter
like settings[*].... (e.g. settings[*].basic.symbol). Instead of giving all
strategies the same value, the tester hands them different values from the list and goes through all unique
combinations. Example: 3 settings files and 10 pairs in values → C(10,3) = 120 runs, in each of which
the strategies trade different pairs. Lets you find the best set of pairs for a portfolio on a shared balance.
monte_carlo - limit the number of runs by random sampling (0 = off). If the total number of sweep
combinations is greater than this value, the tester picks monte_carlo random combinations instead of the full
sweep. Useful when there are millions of combinations: you can quickly "probe" the parameter space and then narrow
the ranges around the best results.
monte_carlo_seed - seed of the random number generator for Monte Carlo (default
42). With the same seed the sample is repeated; change it to get a different sample.
file: config_tester.json/report_optimizer Summary optimizer report:
After a parallel sweep (max_parallel_runs > 1) the tester automatically builds the
report_optimizer_*.html report from reports_history.csv. You can also build it manually —
for example after a sequential sweep, or to rebuild it with different z_parameters: the
manage_tester.bat optimizer command (the --run-report-optimizer flag) takes the
tester/report/{name_comment} folder, or the folder passed as the first argument.
— if 2 or more numeric parameters were swept — heatmaps and 3D surface charts. The X and Y axes show
the two numeric parameters with the most values, the Z axis shows the selected metrics;
— if 1 numeric parameter was swept — line charts of the metrics against that parameter;
— if trading pairs were swept at the same time — charts are built separately for each pair;
— if there is nothing to build charts from — a table of all results is shown in the report.
chart_height - height of the optimizer charts in pixels (550)
z_parameters - list of metrics for the Z axis. Default is
["TotalPnLPercent", "MaxDrawdownPercent", "ProfitFactor"]. You can use any numeric columns
from reports_history.csv: TotalPnL, TotalPnLPercent,
FinalBalance, TotalTrades, WinRate, Fills, MaxDrawdown,
MaxDrawdownPercent, TotalFees, PositionAvgPercent,
PositionMaxPercent, ProfitFactor, as well as the additional columns if they are enabled
in the reports_history section: PnLWithoutTop5, PnLWithoutBestPair,
UlcerIndex, MC_MaxDD_p95, MC_LossProbability.
In reports_history.csv, MaxDrawdown is the maximum drawdown in USDT, and
MaxDrawdownPercent is the worst in % of the report's three drawdowns: Max Drawdown, %,
the % of the peak for Max Drawdown, USDT and Max Unrealized Drawdown, %.
Example 1: sweeping trading pairs
parameter_mining is a list ([]) to which sweep objects are added, separated by
commas ([{}, {}]).
To sweep trading pairs, use the string parameter values, while the numeric fields
start/end/step are set to 1.0 (they are ignored when
values is not empty).
The parameter settings[*].basic.symbol will be applied to all settings files in the
tester/settings_strategy folder:
"parameter_mining": [
{
"name": "settings[*].basic.symbol",
"start": 1.0,
"end": 1.0,
"step": 1.0,
"values": [
"1000BONKUSDT", "1000FLOKIUSDT", "1000LUNCUSDT",
"1000NEIROCTOUSDT", "1000PEPEUSDT", "1000TAGUSDT",
"4USDT", "AAVEUSDT", "ACHUSDT", "ADAUSDT"
]
}
]
Result: the tester will run the test in turn for each of the 10 pairs.
Example 2: sweeping several parameters at once
Let's add, on top of sweeping pairs, a sweep of the take-profit % value — from 0% to 10% in steps of 0.5 (21 values in total).
Number of combinations: 10 pairs × 21 values = 210 runs.
"parameter_mining": [
{
"name": "settings[*].basic.symbol",
"start": 1.0,
"end": 1.0,
"step": 1.0,
"values": [
"1000BONKUSDT", "1000FLOKIUSDT", "1000LUNCUSDT",
"1000NEIROCTOUSDT", "1000PEPEUSDT", "1000TAGUSDT",
"4USDT", "AAVEUSDT", "ACHUSDT", "ADAUSDT"
]
},
{
"name": "settings[*].options.take_profit_long",
"start": 0,
"end": 10.0,
"step": 0.5,
"values": []
}
]
Example 3: setting up a sweep
Video walkthrough
All the bot's strategies are also available in PineScript format for testing on TradingView.