Skip to content

v0.6.8

Latest

Choose a tag to compare

@eeiaao eeiaao released this 26 Jul 10:22

v0.6.8 — one set of stats keys, and the defects behind them

The backtest statistics keys are now consistent across every binding, and a group of defects in the binding surfaces, the CLI and the published artefacts is fixed. This release contains two breaking changes; one of them fails silently, so please read the migration section before upgrading.

Which changes apply to you

Upgrading from Scope
npm 0.6.60.6.8 Everything below. 0.6.7 was never published to npm: its Windows build failed, and the publish step is gated on all three platforms.
PyPI 0.6.70.6.8 Only the Windows addon build fix. Nothing user-facing changed for Python.

The rest of these notes describe the change set relative to 0.6.6.

Breaking changes

Statistics keys are now consistent across bindings. Six producers previously returned six different shapes for the same three risk ratios. They now derive from one source — the C++ BacktestStats field name — mapped to each language's convention.

Binding Previously Now
Python, Codon sharpe, sortino, calmar; BacktestResult.stats() already used sharpe_ratio sharpe_ratio, sortino_ratio, calmar_ratio
Node sharpe / sortino / calmar from BacktestResult.stats(); sharpeRatio alone from runCsv sharpeRatio, sortinoRatio, calmarRatio

Reading an old key does not raise. It returns None in Python and undefined in Node, so the first sign is usually a missing figure in a report or a nan in a summary rather than a stack trace. If you read these keys, search for them before upgrading:

grep -rn "\['sharpe'\]\|\.sharpe\b\|\['sortino'\]\|\['calmar'\]"

Every producer now returns all three ratios. Previously Node's runCsv returned neither Sortino nor Calmar, and Python's run_* omitted Calmar.

Four C API functions changed from void to int.

int flox_fee_schedule_load_profile(FloxFeeScheduleHandle, const char*);
int flox_funding_schedule_load_profile(FloxFundingScheduleHandle, const char*);
int flox_rate_limit_policy_load_profile(FloxRateLimitPolicyHandle, const char*);
int flox_simulated_executor_apply_latency_profile(FloxSimulatedExecutorHandle, const char*);

They return 1 when the profile was applied and 0 when the name is unknown. An unrecognised name was previously a documented no-op, which meant a typo produced a zero-fee, unthrottled backtest that looked healthy. Node, Python and Codon now raise on failure. C consumers that ignore the return value are unaffected at the call site, but the recorded ABI snapshot has changed.

Fixes

  • Published npm binaries no longer carry -march=native. Prebuilds up to and including 0.6.6 were compiled with the build runner's native architecture flags baked into the statically linked archive, which could fault with SIGILL on a consumer CPU missing an instruction the runner had. 0.6.8 is the first prebuild without it. If you saw unexplained crashes at import, this is a likely cause.
  • flox new produced a strategy that never closed a position. Both branches of the generated crossover required ctx.is_flat(), so the position opened once and the exit branch could never fire. Since total_trades counts closed round trips, the first command a new user ran reported zero trades and a flat return. Two of the three templates and five documentation pages carried the same pattern.
  • flox engine sim now starts. It previously raised TypeError on the first call after argument parsing and had never run. It also gains documentation, which did not exist, and a --tape-symbol-id flag: a multi-symbol tape previously delivered another instrument's trades under the requested symbol name, exiting successfully. Multi-symbol tapes now require an explicit choice rather than guessing.
  • All five Node VenueStack static factories work. binanceUmFutures, bybitLinear, okxSwap, deribit and fromVenue threw SyntaxError: Unexpected number — the documented way to construct a stack was unusable.
  • Codon compilation fixes. Because Codon only realises a function where it is called, several methods shipped without ever being compiled: all profile loaders, RateLimitPolicy.add_bucket (the only way to configure a rate-limit policy), all six Partitioner split methods, and run_ohlcv / run_bars / on_book_snapshot.
  • QuickJS. setQueueFifoTopN raised ReferenceError on every call despite being implemented and documented — its global was never registered. tickBars ignored its sides argument, so buyVolume was always zero on that one aggregator, without error.
  • assemble_custom_venue sets a queue model. It previously left QueueModel::NONE, where resting maker orders never fill while taker orders still do, so a backtest built this way appeared to run normally and reported no maker fills.
  • archive binance no longer drops the trade with aggTradeId == 0, which was treated as "nothing archived yet".

New

  • BacktestRunner can be driven against a VenueStack via set_venue_stack(). Passing a stack's executor to set_executor() previously produced a run with zero trades and a flat equity curve, because the runner kept feeding its built-in simulator while fill reporting sat on the custom executor.
  • Fill carries is_maker, and BacktestConfig gains maker_fee_rate / taker_fee_rate. Both default to unset, so existing results do not move. This replaces the previous guidance that feeRate be treated as a maker/taker average, which understates a strategy that mostly posts. The stack's volume-tiered FeeSchedule is still not consulted.
  • VenueStack.clock() returns a usable object. Every call previously raised TypeError: Unregistered type.
  • MCP covers six surfaces instead of four. C++ (2583 symbols) and QuickJS (542) are inventoried for the first time; Codon now lists its own 118 classes rather than the underlying C function names; Python and Node include methods. lookup_symbol resolves methods as Owner.method and lists C++ first, since the other surfaces wrap it.

Build

CMAKE_BUILD_TYPE now defaults to Release. An unset build type was not a neutral choice: without NDEBUG, FLOX_SCALE_CHECKS is enabled and adds a member to Decimal, changing sizeof(Price) from 8 to 16 and the layout of every struct holding a price. A consumer compiling its own translation units against such an archive reads fields at the wrong offsets, which corrupts memory rather than failing to link. The Node addon now refuses to build on a mismatch, and understands multi-config generators such as Visual Studio, where the configuration is chosen at build time rather than at configure time.


Full Changelog: v0.6.7...v0.6.8

For npm, which skipped 0.6.7: v0.6.6...v0.6.8