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.
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.
-
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.
-
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.
-
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 periodcurrentPeriodPlatformProfit— realised house profit this periodlastPeriodResetAt— 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.