Engines and markets

Creating a Binary AI Engine against an AI Market Maker, the ACTIVE/PAUSED/STOPPED lifecycle, win-rate periods and resets, and what every field on the engine detail screen actually changes.

7 min readUpdated 3 August 2026engines, markets, lifecycle, win-rate

An engine is one configuration attached to one market. It holds a target win rate, a set of feature switches, a set of risk limits, and the running counters for the current period. Everything the addon does, it does per engine.

Engines live under Extensions → Binary AI Engine → Engines.

One engine, one market maker, one market

An engine is attached to an aiMarketMaker row, not to a binary market. The column carries a unique index, so a market maker hosts exactly one engine and the create screen only offers market makers that do not already have one.

The chain that gives an engine its symbol is:

binaryAiEngine
  → aiMarketMaker        (owns the published price series)
    → ecosystemMarket    (currency + pair, e.g. BTC/USDT)
      → binaryMarket     (same pair, source must be ECOSYSTEM)

If any link is missing the engine still saves and still shows in the list — it simply never steers anything, and the reason is recorded on every settlement. See Pricing and settlement for the full list of refusal reasons.

Creating an engine

The create screen is a three-step wizard at Engines → Create Engine.

  1. Select Market — pick from the AI Market Makers that do not yet have an engine. The list shows each one's symbol and status. If it is empty, either the market maker addon is not installed, or every market maker already has an engine.

  2. Win Rate Config — set the target user win rate (slider, 20–50%), the variance band around it (±1–15%), the period reset interval in hours, and the maximum price adjustment.

  3. Features — switch on whale detection, user tiers and big-win cooldowns, choose a practice mode, and set the daily loss limit and emergency stop loss.

Anything you leave alone is seeded from the global defaults on the Settings page, not from a hardcoded constant — so the Settings page really is "defaults for new engines". An explicit false or 0 in the wizard is preserved rather than being overwritten by the default.

The create endpoint writes status: "PAUSED" regardless of what you send. You have to activate it deliberately, from the engine detail screen or the engines list. That is intentional: creating an engine should never begin steering money.

The wizard writes an ENGINE_CREATED row to the audit log recording the market maker, the initial target win rate, the variance and the practice mode.

The three states

Status What it means
ACTIVE Loaded in memory, ticking once a second, steering settlements.
PAUSED Unloaded from the tick loop. Open positions settle fairly. Resumable.
STOPPED Same effect as paused, but treated as a deliberate halt. Reactivating runs the full activation checks again.

Changing status goes through the engine manager, which is the single writer of the status column. Each transition writes an audit row (ENGINE_START, ENGINE_PAUSE, ENGINE_STOP).

Activating

Activation has one precondition and it is checked every time: the attached AI Market Maker must be ACTIVE. If it is not, the request comes back as a 400 with "AI Market Maker must be running before activating Binary AI Engine" rather than a server error, because it is a precondition you can fix.

This is deliberately the same test the settlement path uses, so "can be started" and "will be allowed to steer" agree. A live in-memory market maker instance also counts as evidence, which matters when the market maker cron runs in a different process.

Pausing and stopping

Both work whether or not the engine is resident in this process. That was not always true, and it matters after a restart: an engine that is ACTIVE in the database but not yet loaded can still be paused.

Pausing does not cancel open orders. They settle on the honest close, because the settlement hook finds no ACTIVE resident engine and records FAIR:ENGINE_PAUSED.

The response tells you whether it worked

The status endpoint returns engineAttached — whether this process is actually running the engine, not merely recording that it should. An engine that reports status: "ACTIVE" with engineAttached: false is a database row, not a running engine. Check that the cron is registered.

Win-rate periods

The engine does not target a win rate over all time. It targets it over a period, and a period is a window with its own counters:

  • currentPeriodWins / currentPeriodLosses — settled live orders this period
  • currentPeriodPlatformProfit — realised house profit this period
  • lastPeriodResetAt — when the window opened

winRateResetHours (default 24, seeded from the global auto-reset period) decides how long a window lasts. When one comes due — checked about once a minute by the cron — the counters are archived to daily statistics first and then cleared, and a PERIOD_RESET audit row is written. Expired cooldowns are cleaned up at the same time.

Practice mode keeps its own parallel counters (practicePeriodWins, practicePeriodLosses, lastPracticePeriodResetAt) so demo trading can never move the live win rate.

winRateResetHours must be at least 1. At zero, every period is instantly overdue, so the controller resets before it can measure anything and the win-rate target stops working while the engine still reports ACTIVE. The update endpoint now rejects it with a 400, but a row written before that validation existed, or by a direct database edit, will behave this way.

Forcing a reset

Force Period Reset on the engine detail screen archives and clears the current window immediately. There is an includePractice flag for the practice counters. The Settings page has a Reset All Periods button that does the same for every engine at once — it goes through the same archive-then-clear path, so historical data survives.

Use it after you change a target win rate materially. Otherwise the controller spends the rest of the window correcting toward the old number.

The engine detail screen

Five tabs. Every field below is a column on the engine row and takes effect on the next tick after the configuration reloads.

status, optimizationStrategy (CONSERVATIVE / MODERATE / AGGRESSIVE), practiceMode (DISABLED / SAME_AS_LIVE / CUSTOM), simulationMode and logSimulatedActions.

Simulation mode is the per-engine shadow switch: the engine analyses buckets, records what it would have done and writes SIMULATION_RUN audit rows, but no settlement is ever steered. It also removes the engine's per-order exposure cap, because an engine that only observes imposes no limit.

Practice mode decides whether demo orders are steered at all. DISABLED means demo settles naturally at roughly 50%. SAME_AS_LIVE applies the live target. CUSTOM uses practiceTargetWinRate (default 0.55) and practiceWinRateVariance — deliberately outside the live band, because a demo account that always loses does not convert.

targetUserWinRate (0.25–0.45, enforced by the model), winRateVariance (0–0.5), winRateResetHours (1–8760), maxPriceAdjustmentPercent (0 to a hard ceiling of 0.01), adjustmentLeadTimeSeconds (0–3600), volatilityMaskingEnabled and volatilityNoisePercent (0–0.05), and minPositionForOptimization.

The variance is a dead band: while the realised rate sits inside target ± variance the engine reports WITHIN_RANGE and does not force an outcome either way. Widen it and the engine intervenes rarely; narrow it and it intervenes constantly.

adjustmentLeadTimeSeconds is how far ahead of expiry a bucket becomes eligible. At the default 30 seconds, an order placed for a 5-minute expiry is ignored for its first four and a half minutes.

minPositionForOptimization is a floor on the total staked in a bucket. Below it, the bucket is skipped entirely — a single tiny ticket is not worth steering. Set it to 0 to steer every bucket; that genuinely means zero, not "use the default".

enableWhaleDetection, whaleThreshold, whaleStrategy, whaleWinRateCap, whaleProfitMultiplier, enableWhaleAlerts, enableUserTiers and tierCalculationMethod (VOLUME / DEPOSIT / MANUAL).

Covered in Risk controls and Tiers and cooldowns.

enableBigWinCooldown, bigWinThreshold, cooldownDurationMinutes, cooldownWinRateReduction, enableStreakCooldown, streakThreshold and streakCooldownDuration.

bigWinThreshold is an absolute profit amount in the market's quote currency, not a multiplier over anything. A win is "big" when the user's realised profit reaches it.

enableExternalCorrelation, externalPriceSource (BINANCE, COINGECKO or CRYPTOCOMPARE), maxDeviationPercent, enableMlAutoApply, maxDailyLoss, maxSingleOrderExposure, emergencyStopLoss and allowedOrderTypes.

enableMlAutoApply lets the periodic optimiser move the target win rate on its own, bounded by the global adjustment speed. Off by default; see Analytics.

Editing an engine

Every update takes an automatic configuration snapshot before it writes, so any edit is reversible from System → Snapshots. The payload is validated first — before the snapshot — so an out-of-contract edit is rejected as such rather than filling your snapshot history with failed attempts.

The validation is not cosmetic. It exists because several columns had no bounds and could put the engine into states it cannot honour:

Field Bound What a bad value did
maxPriceAdjustmentPercent 0 – 0.01 0.5 stored and applied a 50% price rewrite
winRateResetHours 1 – 8760 0 made every period instantly overdue
maxDailyLoss, maxSingleOrderExposure ≥ 0 negatives disabled the limits
externalPriceSource one of three providers an unknown name reported "enabled" while monitoring stayed down
allowedOrderTypes non-empty, known types an empty array matched nothing

After a successful update the loaded instance is hot-reloaded, so the next tick uses the new numbers without waiting for a restart.

Deleting an engine

Deletion cascades to positions, actions, daily stats, user tiers, cooldowns, snapshots, simulations, A/B tests, cohorts and correlation history for that engine. There is no soft delete and no export step.

If you want the history — and you probably do, since it is the record of every outcome you influenced — set the engine to STOPPED instead.

Binary markets

Markets themselves are core Bicrypto, under Finance → Binary → Markets. Two things there matter to this addon.

Source. A binary market is either EXCHANGE (priced from your connected centralised exchange) or ECOSYSTEM (priced from your own ecosystem market). Only ECOSYSTEM markets can ever be steered. When you create a market and specify ECOSYSTEM, the endpoint verifies that an ecosystem market for that pair really exists and rejects the request if not. When source is omitted, a pair is treated as ECOSYSTEM only if that is the only place it exists, so no existing exchange-backed market can change feed by accident.

Import. The Import action bulk-creates binary markets from your active exchange markets. Those come in as EXCHANGE and are therefore outside the engine's reach — useful for listing, useless for steering.