Skip to content

docs(experiments): assess cTrader Open API and refuse it on charter grounds - #203

Merged
eaitbrahim merged 2 commits into
mainfrom
docs/ctrader-feasibility
Aug 9, 2026
Merged

docs(experiments): assess cTrader Open API and refuse it on charter grounds#203
eaitbrahim merged 2 commits into
mainfrom
docs/ctrader-feasibility

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

cTrader came up as a candidate execution venue. This records the assessment and the answer — no — so the question does not get re-litigated from scratch. No adapter, no dependency, no entry point: the deliverable is the finding.

Closes #201.

The finding

cTrader Open API has no unleveraged spot-ownership primitive. It is not a spot venue with leverage bolted on — leverage, margin, short-symmetry and cash-only P&L are load-bearing in every core message type, and no configuration of the account or the API removes all four at once:

  • ProtoOATrader carries leverageInCents/maxLeverage as always-present account fields; ProtoOAPosition carries usedMargin/marginRate/swap as baseline fields on every position.
  • ProtoOATradeSide SELL opens a short — it is symmetric with BUY, not a disposal of something held. There is no "sell what you own" path.
  • There is no cash-balance-in-asset concept anywhere. Only a deposit-currency balance plus position P&L, so nothing ever represents "you hold 0.1 BTC".
  • The swapFree "Shariah account" does not rescue it: it substitutes a daily rolloverCommission for swap, and touches neither the leverage, the short symmetry, nor the absent custody. It is the answer to one question out of four, and not the one that matters.

The KB already rules on this product class directly, which is what turns the argument from inference into citation: §56.1 as corrected by §66.3 — retail "spot" FX is "perpetually rolled to avoid the actual delivery of the currency," with the interest differential charged for the deferral, so a "spot" label is not evidence of spot settlement. §66.3's litmus test — "transfer of property, substantively or constructively" — is exactly what cTrader fails. §28.1–28.2 name CFDs outright in the gharar exclusion set.

What this changed about our own defences

The assessment was independently reviewed, and the review's most useful finding was that the first draft described keel's gates as stronger than they are. Those corrections are in this PR and matter more than the verdict did — a refusal argued from defences that do not hold is worse than no document:

  • Rail 17 is entries-only and one of two LIVE_STATE_RAILS, so it is skipped in paper. Its input is the operator's attestation, not anything an adapter reports — it fails closed by default, but it is operator-honesty, not adapter-honesty.
  • Rail 19's check does not fail cTrader. EUR-USD parses cleanly as a spot id; this is the two-segment residual guards.py already documents. The rail contributes its charter comment, not its grammar.
  • The curation screen is not a reliable gate against a CFD wrapper at allAssetAttestation is keyed on the base asset with no field for an instrument wrapper, so a BTC CFD reuses BTC's admitted spot attestation. Filed as AssetAttestation cannot express an instrument wrapper, so the curation screen cannot see a CFD #202 rather than papered over.

So the honest count is two gates plus the port's own vocabulary, not three independent gates.

Market data, answered rather than dodged

cTrader's market data is genuinely good, and every gate above is execution-side — so a read-only feed trips none of them and would not touch the broker port at all. The document says so and answers on cost/benefit instead: dealer-quoted marks rather than exchange prints, cross-venue basis against the Coinbase spot universe keel actually trades, an SDK with no release in ~2 years, and disproportionate onboarding. Not worth it today, but explicitly not charter-barred the way execution is — claiming otherwise would be the same overreach the review caught three times.

Evidence, stated honestly

A documentation review, not a live probe. No account was opened, no application registered, no connection made. Protocol claims cite help.ctrader.com/open-api/*; SDK-maintenance claims cite PyPI and GitHub. There is no re-runnable probe script here, unlike the Coinbase asset-class study, and the document says so rather than implying empirical evidence it does not have.

Why nothing was built

An adapter for a venue every rail vetoes would be dead code that reads as capability — it would imply cTrader is a live option pending only wiring. Note this is not a general rule against unwired adapters: keel-broker-robinhood (#192) is deliberately built ahead of the broker-port migration, and it passes the charter gates cTrader fails. The distinction is charter compatibility, not wiring.

Markdown-only; no .py, .toml or test file touched.

eaitbrahim and others added 2 commits August 9, 2026 08:14
…rounds

cTrader has surfaced as a candidate venue. This records why it is refused,
so the question does not get re-litigated from scratch.

The finding is structural, not a missing adapter. Every account cTrader Open
API can express is a leveraged, short-permitting, financing-bearing CFD/FX
account: `leverageInCents`/`maxLeverage` are core `ProtoOATrader` fields,
`usedMargin`/`marginRate`/`swap` are baseline on every `ProtoOAPosition`, and
`ProtoOATradeSide` SELL opens a short rather than disposing of a holding.
There is no message anywhere in the protocol for an unleveraged spot holding,
and no cash-balance-in-asset concept -- only deposit-currency P&L.

The `swapFree` "Shariah account" does not rescue it: it substitutes a daily
`rolloverCommission` for swap, and touches neither the leverage, the short
symmetry, nor the absent custody.

Mapped onto our own gates, three refuse it independently -- rail 17
(`qabd`/withdrawal, fails closed with nothing to ever withdraw), rail 19
(spot-only, whose comment states outright there is no config field to widen),
and the curation screen (`riba_yield`, `dayn` backing). None of these move
when the broker-port migration lands, which is why the doc separates that
temporary blocker from the charter one rather than conflating the two.

Deliberately no package, dependency, entry point or conformance test: an
adapter for a venue every rail vetoes would be dead code that reads as
capability -- the mistake rail 19's own notes record having made once already.

Evidence is a documentation review, not a live probe; no account was opened
and the doc says so rather than dressing it up as empirical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eview

An independent review checked every citation and found the verdict sound but
three of the gates described more strongly than they are. Correcting them
matters more than the conclusion did -- a refusal argued from defences that
do not hold is worse than no document.

- Rail 17 is entries-only and one of two `LIVE_STATE_RAILS`, so it is skipped
  in paper; "vetoes every BUY unconditionally, forever" was wrong. Worse, the
  input is the OPERATOR's attestation (`executor.py:234-257`), not anything an
  adapter reports -- so it fails closed by default but is operator-honesty,
  not adapter-honesty. Said plainly rather than overclaimed.
- Rail 19's grammar check does NOT fail cTrader: `EUR-USD` parses cleanly.
  This is exactly the two-segment residual `guards.py:725-736` already
  documents. The rail contributes its CHARTER comment, not its check, and the
  doc no longer contradicts its own table on this.
- The curation screen is not a reliable gate against a CFD wrapper at all:
  `AssetAttestation` is keyed on the base asset with no field for an
  instrument wrapper, so a BTC CFD reuses BTC's admitted spot attestation.
  Recorded as an open modelling gap instead of a defence we do not have.
- `BrokerCapabilities(asset_classes=frozenset())` constructs fine; the
  non-emptiness comes from `conformance/suite.py:89-98`, not `__post_init__`.

Two additions the review argued for, both load-bearing:

- A real `KB basis:`. The claim that this was "architectural, not a fresh
  halal question" threw away the strongest evidence in the repo. §56.1 as
  corrected by §66.3 is a written ruling on precisely this product -- retail
  "spot" FX perpetually rolled to avoid delivery, interest charged for the
  deferral -- with §66.3's "transfer of property, substantively or
  constructively" as the citable litmus test. §28.1-28.2 name CFDs outright.
  That converts the central claim from inference to citation.
- A "(c) market data only" branch. Every gate here is execution-side, so a
  read-only feed trips none of them and would not touch the broker port.
  Answered on cost/benefit -- dealer-quoted marks, unmaintained SDK,
  disproportionate onboarding -- and explicitly NOT charter-barred, because
  claiming otherwise would be the same overreach as the three above.

Also drops volatile GitHub star/issue counts, widens the evidence statement to
name PyPI/GitHub, and fixes a precedent misattributed to `guards.py` that
actually lives in the Coinbase study.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@eaitbrahim eaitbrahim added compliance Shariah/compliance screening or policy (Compliance & rails) research Measurement, validation or KB work (Research & validation) labels Aug 9, 2026
@eaitbrahim
eaitbrahim merged commit 98029b6 into main Aug 9, 2026
1 check passed
@eaitbrahim
eaitbrahim deleted the docs/ctrader-feasibility branch August 9, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compliance Shariah/compliance screening or policy (Compliance & rails) research Measurement, validation or KB work (Research & validation)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Assess cTrader Open API (openapi.ctrader.com) as a candidate broker for keel

1 participant