Early cancellation, risk limits and the three presets
The per-order-type cancellation rules and their penalties, which penalty tiers are actually reachable, why the two risk-management fields are inert, and what each preset really contains.
Early cancellation lets a customer close a binary contract before it expires and get part of their stake back. It is a refund path with a configurable penalty, and the penalty is the whole product decision: leave it at zero and you have handed every trader a free option — enter, watch, exit for nothing when the price moves the wrong way, and keep the wins.
The other half of this page is the Risk Management tab, which contains two fields that look like safety nets and are not.
Both live on Admin → Finance → Binary Options → Binary Settings
(/admin/finance/binary/settings), on the Cancellation, Risk Management
and Presets tabs. Reading the console needs access.binary.settings; saving
needs edit.binary.settings.
The two switches above every rule
cancellation.enabled is the global one. With it off, the cancel route refuses
everything with 400 "Order cancellation is disabled", whatever the per-type
rules say.
Under it, each of the five order types has its own CancellationRule, and each
carries its own enabled. A type whose rule is off is refused with
400 "Cancellation is not available for <TYPE> orders".
What a rule contains
| Field | Meaning |
|---|---|
enabled |
Whether this order type may be cancelled at all. |
minTimeBeforeExpirySeconds |
The cutoff. Cancellation is refused once the contract is at or inside this many seconds of expiry, with a 400 naming the figure and the time remaining. |
penaltyPercentage |
Percentage of the stake kept by the platform, 0–100. The customer receives stake − penalty. |
penaltyByTimeRemaining |
Optional. Three tiers — above60Seconds, above30Seconds, below30Seconds — chosen by how long is left. |
If penaltyByTimeRemaining exists on a rule, the server never reads
penaltyPercentage for that type. It picks a tier by time remaining and uses
it:
| Time to expiry | Tier used |
|---|---|
| more than 60 seconds | above60Seconds |
| more than 30, up to 60 seconds | above30Seconds |
| 30 seconds or less | below30Seconds |
So the Penalty % box on a card that also shows three tier boxes is decorative. It is still saved, still validated, and still ignored.
You can edit the three tiers from the screen only if the rule already has them. The console renders that block conditionally, so a type shipped without tiers — Touch/No Touch and Turbo on the defaults, and every type under the conservative preset — offers no way to add them.
Some tiers can never fire
minTimeBeforeExpirySeconds is enforced before the tier is chosen, so a
cutoff at or above a tier boundary makes the tiers below it unreachable. On the
shipped defaults:
| Type | Cutoff | Reachable penalties | Unreachable |
|---|---|---|---|
RISE_FALL |
30s | 5% over 60s, 10% between 30 and 60s | below30Seconds 20%, and the flat 10% |
HIGHER_LOWER |
30s | 10% over 60s, 15% between 30 and 60s | below30Seconds 25%, and the flat 15% |
CALL_PUT |
60s | 10% — the only tier that can ever apply | both other tiers, and the flat 15% |
TOUCH_NO_TOUCH |
60s | rule is disabled by default | — |
TURBO |
0s | rule is disabled by default | — |
Call/Put is the clearest case: a 60-second cutoff means every permitted cancel
happens with more than 60 seconds left, so above60Seconds is the answer every
time and the other three numbers on the card are noise.
If you want the graduated penalties to actually grade, the cutoff has to be below 30 seconds.
The shipped rules
| Type | Enabled | Cutoff | Flat penalty | Graduated (60s / 30s / under) |
|---|---|---|---|---|
RISE_FALL |
yes | 30s | 10% | 5 / 10 / 20 |
HIGHER_LOWER |
yes | 30s | 15% | 10 / 15 / 25 |
TOUCH_NO_TOUCH |
no | 60s | 20% | none |
CALL_PUT |
yes | 60s | 15% | 10 / 15 / 25 |
TURBO |
no | 0s | 0% | none |
Touch/No Touch and Turbo ship disabled because both can be gamed: a Touch contract whose barrier has already been hit is a certain win the customer would otherwise cancel out of, and a Turbo contract is too short for an early exit to mean anything.
What the server checks, in order
-
The order exists, belongs to the caller and is
PENDING. -
cancellation.enabled, then the per-typeenabled. -
minTimeBeforeExpirySecondsagainst the time left. Refused with a 400 naming both numbers. -
Barrier state, for
TOUCH_NO_TOUCHandTURBO. A Touch contract whose barrier has already been touched, or a Turbo contract whose barrier has been breached, is refused. A Turbo contract on aTICKSduration cannot be cancelled at all. -
The penalty is computed server-side from the rule, and any
percentagein the request body is deliberately ignored — otherwise a customer could post0and cancel for a full refund. -
A distributed lock is taken on the order — the same lock settlement uses — and the order is re-read
FOR UPDATEinside the transaction and abandoned if it is no longerPENDING. That is what stops a cancel racing a payout. -
The refund is credited, the row is set to
CANCELEDwithprofit: 0and the close price of the moment, andmetadatarecordsrefundedAmountandcancelPenalty.
Both barrier checks read candle history from the centralised exchange provider. If that lookup throws, the code logs a warning and allows the cancellation — the customer gets the benefit of the doubt.
On a market whose source is ECOSYSTEM there is no exchange to ask, so the
checks do not run at all: TOUCH_NO_TOUCH is skipped outright and TURBO
treats the barrier as unbreached. If you enable early cancellation on those two
types, do it on EXCHANGE-sourced markets. See
Binary markets.
cancelExpirationBuffer does not do what its name suggests
global.cancelExpirationBuffer (default 60) is published to the trading page
through the public binary settings endpoint. That is the entire extent of it:
- Nothing on the server reads it. The only cutoff the cancel route enforces
is the per-type
minTimeBeforeExpirySeconds. - Nothing on the trading page reads it either. The customer's cancel button is enabled while more than 10 seconds remain, hard-coded; the cash-out button needs 30 seconds since entry and 10 to expiry, also hard-coded.
So on a default install a customer sees a live cancel button from 30 seconds
down to 10 seconds before expiry and gets an error if they press it, because the
RISE_FALL cutoff is 30 seconds. Two ways to make the screen and the server
agree:
- set
minTimeBeforeExpirySecondsto 10 or less for every enabled type, so the button and the server refuse at the same moment; or - accept the error and keep the wider cutoff, which is the safer commercial choice — a contract cancelled 11 seconds before expiry is very close to a free look at the outcome.
Set cancelExpirationBuffer to match whichever you choose anyway. It costs
nothing and a future release may start honouring it.
Demo contracts never move money
Every wallet operation in the binary order service sits behind if (!isDemo).
A practice contract is cancelled, refunded and settled entirely on paper — no
wallet is read, no transaction row is written, no penalty is taken. Cancellation
rules still apply to demo orders in every other respect, so practice is a safe
place to check that a rule behaves the way you expect.
Risk Management
Two fields, on their own tab.
| Field | Shipped default | The screen says |
|---|---|---|
riskManagement.dailyLossLimit |
0 |
"Daily Loss Limit (trades)" — auto-pause trading after this many |
riskManagement.winRateAlert |
65 |
alert when a user's win rate exceeds this percentage |
There is no code path anywhere in the platform that pauses trading when
dailyLossLimit is exceeded, and none that raises an alert when a user's win
rate passes winRateAlert. Both values are written into the binarySettings
row, returned by the admin GET, rendered on this tab — and consumed by exactly
one thing: the settings validator, which raises an info warning when
dailyLossLimit is 0.
That warning is the source of the widespread belief that 0 means "disabled".
It is accurate as far as it goes — 0 does mean nothing happens — but so does
every other value.
Do not treat either field as a control. If you need a daily loss stop, it
has to come from the limits that are enforced: global.maxDailyOrders,
global.maxConcurrentOrders and global.cooldownSeconds, plus per-market
minAmount / maxAmount on the binary market row. Those are on
Binary options: switching it on and
Binary markets.
For monitoring the exposure by hand, the analytics on the binary order desk carry live-only net house P&L, outstanding payout liability and user win rate — see The binary order desk.
The field label also disagrees with itself: it is titled "(trades)" and described as a loss limit. Since nothing reads it, the ambiguity has no consequence today, but it means you cannot infer the intended unit from the screen.
The three presets
The Presets tab offers three complete configurations. Each is returned by its own endpoint with a human-written description, a feature list, a risk level and its own validation result.
Conservative — riskLevel: low
Described as: only RISE_FALL enabled, tight barrier distances (0.1%–0.3%),
lower max amounts ($10–$500), a 50–70% profit range, a 5-second cooldown, and a
daily loss limit enabled.
What it actually sets, for this page's subjects:
| Value | |
|---|---|
| Cancellation | on; no graduated tiers on any type; cutoffs 45s (Rise/Fall, Higher/Lower) and 90s (Touch, Call/Put); flat penalties 15 / 20 / 25 / 20 / 0 |
dailyLossLimit |
1000 |
winRateAlert |
60 |
| Durations | four rungs only — 1, 3, 5 and 15 minutes |
Balanced — riskLevel: medium, and the shipped default
Described as: only RISE_FALL, moderate barriers (0.1%–0.5%), standard amounts
($1–$1,000), a 65–85% profit range, no cooldown, configurable risk limits.
| Value | |
|---|---|
| Cancellation | on; the shipped rules table above |
dailyLossLimit |
0 |
winRateAlert |
65 |
| Durations | eight rungs, 1 minute to 1 hour |
Aggressive — riskLevel: high
Described as: RISE_FALL and HIGHER_LOWER enabled, wider barriers
(0.1%–1%), higher max amounts ($1–$10,000), a 55–90% profit range, no cooldown,
relaxed risk limits, extended durations.
| Value | |
|---|---|
| Cancellation | on for all five types, including Touch and Turbo; cutoffs 15s / 15s / 30s / 30s / 10s; Turbo carries a flat 25% penalty |
dailyLossLimit |
0 |
winRateAlert |
75 |
| Durations | nine rungs, including a 4-hour one |
The bullet lists on the Presets tab are hand-written descriptions, not generated from the objects. Where they disagree, the object is what gets saved.
- The amounts do not exist. There is no minimum or maximum stake anywhere in
the binary settings document. Stake bounds are
minAmountandmaxAmounton each binary market row, and no preset touches them. "$10–$500" and "$1–$10,000" describe nothing that will change. - Balanced does have a cooldown. The list says "no cooldown between orders";
global.cooldownSecondsin the balanced preset is 3. - Aggressive does not reach 1% barriers. Its widest Higher/Lower barrier is 0.5%, at a 42% payout. Nothing in it goes to 1%.
Applying one replaces everything
The Presets tab does setSettings(preset.settings) — the whole settings
document is swapped, including every payout, every barrier ladder, the duration
rungs, the cancellation rules and the risk fields. It is not a merge and it does
not preserve anything you had configured.
Like the optimizer, it stages the change: the floating unsaved-changes bar appears and nothing is written until you press Save. Discard restores what was loaded.
Two metadata fields ride along on the object:
_preset— the preset name, which is what the tab reads back to show which one is currently applied. An install that has never saved reportsbalanced, because the defaults are the balanced preset._lastModified— an ISO timestamp. The PUT overwrites it with the moment of the save, so on a saved row it is the last time anybody pressed Save, not when the preset was authored.
The validation object
Both the GET and the PUT return validation: { valid, errors, warnings }, and
the presets endpoint returns one per preset — so you can see a preset's warnings
before applying it.
Errors block the save. The PUT answers 400 and writes nothing. Warnings do not block anything; each is an object:
| Field | Is |
|---|---|
level |
info, warning or danger |
category |
Barrier Risk, Profitability, Configuration, Risk Management |
message |
what is wrong, with the offending number in it |
suggestion |
what to do about it |
field |
the dotted path, e.g. orderTypes.HIGHER_LOWER.barrierLevels — absent on the two warnings that are about the configuration as a whole |
The ones you will meet on this page's settings:
| Level | Warning |
|---|---|
info |
"No daily loss limit is configured" — raised whenever dailyLossLimit is 0, which is the shipped default |
info |
Touch profit under 150% is low for a difficult trade type |
warning |
Turbo's maxDuration is over 5 minutes |
danger |
no durations are enabled — trading will not work |
The full list, including the barrier-distance and average-payout warnings, is on Binary options: switching it on.
Deciding a cancellation policy
-
Start with cancellation off if you have no view on it. Nothing about the product needs it, and it is a strictly negative-margin feature until you have priced the penalty.
-
Never set a penalty to 0 on an enabled type. A free cancel is a free option: the customer keeps every trade that is going their way and exits every one that is not.
-
Set the cutoff before the penalty. If you want the graduated tiers to do anything,
minTimeBeforeExpirySecondsmust be under 30 — otherwise the nearest tier is the only one that fires. -
Leave Touch/No Touch and Turbo disabled unless every market you offer them on is
EXCHANGE-sourced. The barrier checks that make cancellation safe on those types do not run on ecosystem markets, and fail open when the price feed errors. -
Do not rely on the Risk Management tab. Configure the enforced limits on the Global Settings tab instead, and watch the desk's analytics.
-
Test on a practice account. Demo contracts follow the same rules and move no money, so you can confirm the penalty and the cutoff behave as configured before a customer meets them.
Related: Barriers, strikes and the payout optimizer, Order types, durations and payouts, and The binary order desk for reading a cancelled contract after the fact.