Logo hamster-bot Claude new: MCP
RU EN PT

Loading…


hw98_console_prompt.avif Testing trading strategies on historical data

A reliable portfolio backtest. Quant-research level quant

First run of the tester video first run of the tester Update overview and parameter optimizer video update overview and parameter optimizer Sweep and analysis. Building heatmaps and 3d Surface video Sweep and analysis. building heatmaps and 3d surface Strategy tester. Instructions for running tests. Sweeping trading pairs. video instructions for running tests. sweeping trading pairs Strategy tester. Guide to the new tester web interface. video guide to the new tester web interface Strategy tester. Parameter sweep in a backtest. video parameter sweep in a backtest Strategy tester. Instructions. Three testing scenarios. video instructions. three testing scenarios

hamster-bot/tester - an advanced tool for testing trading systems on historical data.

Backtester features:

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.

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.

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.

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:

Charts:

Report Statistics — detailed statistics:

Details — detail tabs:

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 Video walkthrough

All the bot's strategies are also available in PineScript format for testing on TradingView.