Konzept Mehrere Handelsplattformen: Polymarket US, spaeter Kalshi (#622-#629)

Ein Kunde mit US-Wohnsitz soll ueber Polymarket US handeln - eine eigene,
CFTC-regulierte Boerse, an der die heutige CLOB-Anbindung nicht verwendbar ist.
Das Konzept macht Plattform zu einem Begriff im Core, laesst Module ihre
Plattformen erklaeren und haelt Strategievarianten je Plattform im Modul.

Begruendungen zu #622-#629 in docs/ROADMAP.md, Bauanleitung in
docs/archiv/konzepte/KONZEPT-Multi-Plattform.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-18 10:54:00 +02:00
co-authored by Claude Opus 5
parent 94716157cf
commit 05979406c7
3 changed files with 445 additions and 0 deletions
+95
View File
@@ -408,6 +408,80 @@ Abgleich der unabhängig erhobenen Buchhaltung gegen die eigene Trading-DB. Nied
aber der eigentliche Prüfwert des Moduls: **Abweichungen zwischen beiden Quellen sind das
Signal.**
### Mehrere Handelsplattformen (#622–#627)
**Anlass (16.09.2026):** Ein Kunde mit Wohnsitz in den USA kann KYC machen. polymarket.com sperrt
US-IPs, er muss über **Polymarket US** handeln — eine eigene, CFTC-regulierte Börse mit eigener
API. Von der heutigen CLOB-Anbindung ist dort nichts verwendbar: andere Anmeldung (Ed25519 statt
EIP-712/HMAC), Märkte per Slug statt Token-ID, USD statt USDC, automatische Abwicklung statt
Redeem, andere Gebührenformel, eigener Liquiditätspool.
Richard hat entschieden: Wir bauen nicht nur einen zweiten Adapter, sondern machen **Plattform zu
einem Begriff im Core**, damit später Kalshi ein weiterer Adapter ist und kein weiterer Umbau.
Module erklären ausdrücklich, welche Plattformen sie bedienen; Strategien dürfen sich je Plattform
unterscheiden.
**Warum in B und nicht in C:** Es entsteht kein neues Strategiemodul, sondern ein weiterer Weg, die
gebauten Module an echtes Geld zu bringen. Die Abhängigkeit von A bleibt: Ohne Betriebsfreigabe
(#621) und Feldtest handelt auch der US-Kunde nicht live.
**Die zwei Auflagen, die das Konzept trägt:**
1. **Der Global-CLOB-Code wird umhüllt, nicht umgebaut.** `PolymarketClobClient` bleibt Zeile für
Zeile, wie er ist; der Global-Adapter übersetzt nur. Ein Fundament, das den bewährten Geldpfad
verändert, wäre teurer als der US-Kunde wert ist.
2. **Die Plattform-Erklärung eines Moduls wirkt im Handelspfad**, nicht nur in der Anzeige. Das
Order-Gateway lehnt ab, was das auslösende Modul nicht erklärt hat — dieselbe Lehre wie #569/#570.
→ [archiv/konzepte/KONZEPT-Multi-Plattform.md](./archiv/konzepte/KONZEPT-Multi-Plattform.md)
### [B] #622 — PL-0: Voraussetzungen für den US-Kunden klären
Keine Programmierarbeit, aber ohne sie ist #625 nur lesend baubar: API-Schlüssel des Kunden,
Serverstandort (US-Standort gegen US-IP-Sperre von polymarket.com), ob es für die Retail-API eine
Testumgebung gibt, und unsere Rolle beim automatisierten Handel auf einem fremden KYC-Konto.
### [B] #623 — PL-1: Plattform-Fundament im Core
`PlatformId`, `PlatformCapabilities`, neutrale Verträge mit `InstrumentRef` statt `TokenId`,
Registry, Global-Adapter als Hülle, Spalte `platform` mit Vorgabe `polymarket-global`.
**Akzeptanz: Verhalten unverändert, Diff an `PolymarketClobClient.cs` leer.** `TokenId` steht in
73 Dateien — deshalb bleibt es als Eigenschaft erhalten und zieht schrittweise um.
### [B] #624 — PL-2: Module erklären ihre Plattformen
**Auslöser: sobald #623 abgeschlossen ist.**
`IPolyTraderModule.SupportedPlatforms` mit Vorgabe „nur Global" — ein Modul, das nichts erklärt,
verhält sich wie heute. Kennzeichen in Modul-Tab und Kontenansicht (Desktop und WebUI aus einer
Core-Regel, wie seit #560), Warnung bei Konten ohne Modul, Sperre im Order-Gateway.
Warum Erklärung **und** Fähigkeiten: Dass eine Plattform alles Nötige *hat*, heißt nicht, dass die
Strategie dort *geprüft* ist.
### [B] #625 — PL-3: Adapter Polymarket US
**Auslöser: sobald #623 abgeschlossen ist; echte Orders zusätzlich erst nach #622.**
Erst lesend, dann Demo gegen das echte US-Buch, dann Orders. Die Retail-API hat keine dokumentierte
Sandbox — Demo gegen Produktion ist damit der einzige Weg zur Messphase.
### [B] #626 — PL-4: ResolutionFarming für Polymarket US
**Auslöser: sobald #624 und #625 abgeschlossen sind.**
Erste Strategie für den US-Kunden, weil sie keine fremden Wallet-Daten braucht. Die US-Gebühr
`Θ·p·(1−p)` ist nahe 0,95 sehr klein, Maker bekommen einen Rabatt, und der Redeem (#146) entfällt.
Global-Schwellen sind wegen des getrennten Pools **nicht** übertragbar — Startwerte kommen aus der
Messphase.
### [B] #627 — PL-5: Accounting für Polymarket-US-Konten
**Auslöser: sobald #625 abgeschlossen ist.**
Keine Chain, keine Data-API: Aktivität, Saldo und Balance-Ledger kommen aus der US-API, in USD.
Macht nebenbei #147 (US-Steuerschicht) greifbar — der US-Kunde ist genau dieser Fall.
---
## C — Neue Strategiemodule
@@ -543,6 +617,27 @@ keine API existiert. Berührt auch #151 — die Fingerprint-Baseline wäre von d
Prüfplan: [pruefplaene/PREDICTALYTICS-PRUEFPLAN-Master-Auswahl.md](./pruefplaene/PREDICTALYTICS-PRUEFPLAN-Master-Auswahl.md)
### [D] #628 — PL-6: CopyTrading plattformübergreifend
**Auslöser: sobald #625 abgeschlossen ist und Richard entschieden hat, ob sich das lohnt.**
Auf Polymarket US sind fremde Wallets nicht sichtbar; CopyTrading hat dort keine eigenen Master.
Denkbar wäre: Master weiter auf Polygon beobachten, auf dem passenden US-Markt ausführen.
**Warum nicht beschlossen:** Nicht jeder Markt existiert in den USA, der Pool ist getrennt, Kurse
und Gebühren weichen ab — der Einstieg liegt systematisch anders als beim Master, und genau dieser
Abstand entscheidet heute über die Rentabilität (#163).
→ [archiv/konzepte/KONZEPT-Multi-Plattform.md](./archiv/konzepte/KONZEPT-Multi-Plattform.md)
### [D] #629 — PL-7: Adapter Kalshi
**Auslöser: sobald #623 abgeschlossen ist und ein Kunde Kalshi konkret braucht.**
Vorbereitet, nicht beschlossen. Zugleich der Prüfstein für #623: Kommt der Adapter ohne Änderung an
einem Modul aus, trägt die Abstraktion.
→ [archiv/konzepte/KONZEPT-Multi-Plattform.md](./archiv/konzepte/KONZEPT-Multi-Plattform.md) §7
---
## T — Technische Schuld
+1
View File
@@ -42,6 +42,7 @@ Was hier **nicht** mehr gilt, ist der **Status**. Fortschrittsangaben, Häkchen
| `KONZEPT-Modul-Accounting.md` | A-1/A-2/A-4 ✅, A-3 ist **B6**, A-5 ist **B7** |
| `KONZEPT-Modul-Supervisor.md` | S-0–S-4 ✅, Live-Key-Test ist **B5** |
| `KONZEPT-Modul-DataDriven.md` | **D1** — nicht beschlossen, es gibt keinen Umsetzungsplan |
| `KONZEPT-Multi-Plattform.md` | #622–#627 (B), #628–#629 (D) — Polymarket US, Plattform-Abstraktion, Kalshi |
### Einzeldokument
@@ -0,0 +1,349 @@
# Konzept: Mehrere Handelsplattformen (Polymarket US, später Kalshi)
**Angelegt am 16.09.2026.** Planungsstand und Reihenfolge stehen im Deploymentcenter
(Items #622–#629), nicht hier. Diese Datei ist die Bauanleitung und die Begründung.
---
## 1. Anlass und Ziel
Ein Kunde mit Wohnsitz in den USA soll PolyTrader nutzen. Er darf polymarket.com nicht verwenden
(US-IPs gesperrt), wohl aber **Polymarket US** — eine eigene, CFTC-regulierte Börse (QCX LLC als
Designated Contract Market, QC Clearing LLC als Clearingstelle) mit KYC. Der Kunde kann KYC machen.
Polymarket US ist technisch **ein anderer Handelsplatz**, nicht eine Variante desselben. Keine
Zeile der heutigen CLOB-Anbindung ist dort verwendbar (siehe Abschnitt 2). Daraus folgen drei Ziele:
1. **Ein zweiter Plattform-Adapter** für Polymarket US.
2. **Plattform als Konzept im Core**, sodass ein dritter Handelsplatz (Kalshi) ein weiterer Adapter
ist und kein weiterer Umbau.
3. **Module erklären, welche Plattformen sie bedienen können** — sichtbar in Desktop und WebUI und
wirksam im Handelspfad. Strategien dürfen sich je Plattform unterscheiden.
---
## 2. Was Polymarket US anders macht
Quelle: offizielle Doku `https://docs.polymarket.us` (Stand 16.09.2026). Vor dem Bau erneut prüfen —
die Plattform ist jung und ändert sich (Gebühren wurden am 16.09.2026 angehoben).
| | Polymarket Global (heute) | Polymarket US |
|---|---|---|
| Endpunkte | CLOB, Gamma, Data-API getrennt | `api.polymarket.us` (authentifiziert), `gateway.polymarket.us` (öffentlich) |
| Echtzeit | CLOB-WSS, Alchemy/Polygon | `wss://api.polymarket.us/v1/ws/private` (Orders, Positionen, Saldo), `/v1/ws/markets` (Buch, Trades; max. 10 Märkte je Verbindung) |
| Anmeldung | L1 EIP-712 mit Wallet-Key → L2 HMAC (apiKey/secret/passphrase) | Key-ID + Ed25519-Secret; Header `X-PM-Access-Key`, `X-PM-Timestamp` (ms, ±30 s), `X-PM-Signature` = Base64(Ed25519(`timestamp + method + path`)) |
| Konto | Wallet / Proxy-Wallet, kein KYC | KYC-Person (iOS-App), Schlüssel unter `polymarket.us/developer`, Secret wird **nur einmal** angezeigt |
| Markt-Identität | conditionId + tokenId je Ausgang | `marketSlug`; Ausgang über `intent` bzw. `outcomeSide` YES/NO |
| Order | signierte Order (EIP-712), Preis als Zahl, FOK/GTC/GTD | `POST /v1/orders`: `intent` (`BUY_LONG`, `SELL_LONG`, `BUY_SHORT`, `SELL_SHORT`), `price {value, currency}`, `quantity` oder `cashOrderQty`, TIF `DAY/GTC/GTD/IOC/FOK`, `participateDontInitiate` (Post-only), `manualOrderIndicator`, `synchronousExecution` |
| Weitere Order-Wege | — | Modify, Preview, Close-Position, Sammel-Orders, Cancel-All |
| Geld | USDC auf Polygon | USD per Karte, ACH, Wire |
| Abwicklung | On-Chain-Redeem nötig (#146) | automatisch zu 1 $ / 0 $, kein Redeem |
| Gebühr | Taker in bps je Kategorie (`FeeModel`) | `Θ · C · p · (1−p)`; Taker Θ = 0,0695 (ab 16.09.2026), Maker-Rabatt Θ = −0,0125; Banker's Rounding auf Cent |
| Limits | eigene je Endpunkt | 20 Anfragen/s je Schlüssel bzw. je IP; 429 → Backoff. „Global Rate Limit Exceeded" nach 5 s ist Latenzschutz, **kein** Limit |
| Testumgebung | — | Retail-API: keine dokumentierte Sandbox. Preprod nur für die Exchange-API (OAuth), Zugang über onboarding@polymarket.us |
| Liquidität, Marktangebot | globaler Pool, voll | eigener US-Pool, kleineres Angebot |
**Zwei Folgen, die das Design bestimmen:**
- Die **Gebührenformel** ist eine andere *Form*, nicht nur ein anderer Satz. Ein „Satz in bps" reicht
als Modell nicht. Nahe 0,95 ist die US-Gebühr winzig, bei 0,50 am höchsten.
- **Fremde Wallets sind nicht sichtbar.** Alles, was CopyTrading heute beobachtet (Polygon-Logs,
Data-API-Activity), gibt es für den US-Pool nicht.
---
## 3. Ist-Zustand im Code
PolyTrader ist modular (Core + Module), aber **Polymarket Global ist überall stillschweigend
vorausgesetzt**:
| Stelle | Bindung |
|---|---|
| [`IClobClient`](../../../src/PolyTrader.Core/Services/IClobClient.cs) | `tokenId`, `isNegRisk`, `actualFeeBps`, Decimals-Overrides — CLOB-Begriffe im Vertrag |
| [`PolymarketClobClient`](../../../src/PolyTrader.Core/Services/PolymarketClobClient.cs), [`PolymarketApiService`](../../../src/PolyTrader.Core/Services/PolymarketApiService.cs) | direkt von Modulen aufgelöst; Registrierung von `IClobClient` sogar im CopyTrading-Modul |
| [`AccountState`](../../../src/PolyTrader.Core/Models/AccountState.cs) | `WalletAddress`, `ApiPassphrase`, `PrivateKey` — Global-Zugangsdaten als feste Felder |
| [`Position`](../../../src/PolyTrader.Core/Models/Position.cs), `core_positions` | Primärschlüssel `(AccountId, IsDemo, TokenId)` |
| [`MarketData`](../../../src/PolyTrader.Core/Models/MarketData.cs), `core_markets` | `ConditionId`, `ClobTokenIds`, `NegRisk` |
| [`FeeModel`](../../../src/PolyTrader.Core/Trading/FeeModel.cs) | statisch, bps je Kategorie |
| `Streaming/AlchemyWssClient`, `BlockchainWss` | Polygon |
| CopyTrading | 10 Dateien gegen CLOB/API/Chain |
| ResolutionFarming | hat schon `IFarmingMarketSource`, `IMarketResolutionSource` — **gutes Vorbild** |
| Accounting | hat schon `IActivitySource`, `ITransferSource`, `IBalanceAnchorSource` — ebenso |
| Supervisor | nur `CounterfactualJob` liest über die API |
`TokenId` kommt in 73 Dateien vor. Ein Umbau in einem Schritt ist ausgeschlossen.
---
## 4. Leitentscheidungen
1. **Die Plattform gehört zum Konto, nicht zur Installation.** Eine Installation kann Konten
mehrerer Plattformen führen. Ob der Netzweg das zulässt (US-Standort gegen US-IP-Sperre von
polymarket.com), ist eine Betriebsfrage (#622), keine Architekturfrage.
2. **Der Global-CLOB-Code wird umhüllt, nicht umgebaut.** Signierung, Betragsrechnung und
Orderablauf von `PolymarketClobClient` bleiben Zeile für Zeile, wie sie sind. Der
Global-Adapter übersetzt nur zwischen neutralem Vertrag und bestehendem Client. Das ist die
direkte Anwendung von `.agents/rules/clob.md`.
3. **Module sprechen gegen Plattform-Verträge**, nicht gegen `Polymarket*`-Klassen. Das Muster
existiert schon in ResolutionFarming und Accounting und wird verallgemeinert.
4. **Logik fragt nach Fähigkeiten, nicht nach Namen.** `if (caps.PublicTraderActivity)` statt
`if (platform == PolymarketGlobal)`. Ein neuer Handelsplatz bringt seine Fähigkeiten mit, und
bestehende Module entscheiden richtig, ohne ihn zu kennen.
5. **Module erklären ihre Plattformen ausdrücklich.** Fähigkeiten allein reichen nicht: Dass eine
Plattform alles Nötige *hat*, heißt nicht, dass die Strategie dort *geprüft* ist. Die Erklärung
ist eine Freigabe, die Fähigkeiten sind eine Plausibilitätsprüfung.
6. **Strategievarianten leben im Modul**, als Profil je Plattform — kein „ResolutionFarmingUS"-Modul.
Die fachliche Idee bleibt eine; Gebühren, Schwellen und Marktquelle unterscheiden sich.
7. **Global bleibt die Vorgabe.** Jede neue Spalte bekommt `polymarket-global` als Standardwert.
Bestehende Installationen merken nach der Migration nichts.
---
## 5. Architektur
### 5.1 Plattform und Fähigkeiten
```csharp
namespace PolyTrader.Core.Platforms;
/// Stabile Kennung, wird in der Datenbank gespeichert – nie umbenennen.
public readonly record struct PlatformId(string Value)
{
public static readonly PlatformId PolymarketGlobal = new("polymarket-global");
public static readonly PlatformId PolymarketUs = new("polymarket-us");
public static readonly PlatformId Kalshi = new("kalshi");
}
public sealed record PlatformCapabilities(
bool PublicTraderActivity, // fremde Trades beobachtbar (CopyTrading)
bool OnChainSettlement, // Redeem nötig, Chain-Transfers als Buchungsquelle
bool PostOnlyOrders,
bool OrderModify, // Preis ändern ohne Cancel+Neu
bool MakerRebate,
bool FractionalQuantity,
bool NativeDemoEnvironment, // echte Testumgebung der Plattform
IReadOnlySet<TimeInForce> TimeInForce,
string SettlementCurrency); // "USDC", "USD"
```
### 5.2 Verträge
Neutral formuliert, je Plattform einmal implementiert. Aufgelöst über eine Registry, nie direkt.
| Vertrag | Aufgabe | Global-Adapter hüllt | US-Adapter spricht |
|---|---|---|---|
| `IMarketCatalog` | Märkte suchen, nach Enddatum/Kategorie filtern, Auflösungsstatus | Gamma-API, `MarketSyncService` | `gateway` Markets/Events/Settlement |
| `IOrderBookSource` | Buch, BBO | CLOB `/book` | `gateway` Book/BBO |
| `IOrderGateway` | Platzieren, Ändern, Canceln, offene Orders | `PolymarketClobClient` | `POST/…/v1/orders` |
| `IPortfolioSource` | Positionen, Saldo, Aktivität | Data-API, Chain | Portfolio, Account-Balances |
| `IMarketStream` / `IAccountStream` | Echtzeit | CLOB-WSS, Alchemy | `/v1/ws/markets`, `/v1/ws/private` |
| `IFeeModel` | Gebühr für (Preis, Menge, Rolle) | heutiges `FeeModel` | `Θ·C·p·(1−p)` |
| `ISettlementHandler` | Was nach Auflösung zu tun ist | Redeem (#146) | nichts, nur Abgleich |
| `ITraderActivitySource` | fremde Trades | Polygon, Data-API | **nicht vorhanden** |
> **Stand nach #623 (18.09.2026):** Gebaut sind `IMarketCatalog`, `IOrderBookSource`, `IOrderGateway`,
> `IPortfolioSource`, `IFeeModel`, gebündelt in `IPlatformAdapter` (`src/PolyTrader.Core/Platforms/`).
> Die Streams, `ISettlementHandler` und `ITraderActivitySource` entstehen **mit ihrem ersten zweiten
> Nutzer**, nicht auf Vorrat: Streams mit #625, Abwicklung mit #146 bzw. #625, Trader-Aktivität mit #628.
> Die Registry löst den ganzen Adapter auf (`registry.ForAccount(account).Orders`), nicht einzelne
> Verträge per Typ.
```csharp
public interface IPlatformRegistry
{
IReadOnlyList<PlatformId> Available { get; }
PlatformCapabilities Capabilities(PlatformId p);
T Get<T>(PlatformId p) where T : class; // wirft, wenn Plattform den Vertrag nicht hat
bool TryGet<T>(PlatformId p, out T? service) where T : class;
}
```
`IClobClient` bleibt bestehen, bis CopyTrading umgestellt ist; `IOrderGateway` für Global delegiert
darauf. Es gibt keinen Tag, an dem beides gleichzeitig umgeschrieben wird.
### 5.3 Instrument und Order
```csharp
/// Ein handelbarer Ausgang auf einer Plattform. Key ist innerhalb der Plattform eindeutig.
/// Global: Key = tokenId, MarketKey = conditionId
/// US: Key = "{marketSlug}:YES", MarketKey = marketSlug
/// Kalshi: Key = "{ticker}:YES", MarketKey = ticker
/// Gleichheit nur über (Platform, Key).
public sealed record InstrumentRef(PlatformId Platform, string Key, string MarketKey = "", string Outcome = "");
public sealed record OrderRequest(
InstrumentRef Instrument,
OrderSide Side, // Buy / Sell (US: → intent BUY_LONG usw.)
decimal LimitPrice, // immer Wahrscheinlichkeit 0..1 – Adapter rechnet um (Kalshi: Cent)
decimal? Quantity, // Kontrakte/Shares
decimal? NotionalUsd, // alternativ Betrag
TimeInForce Tif,
bool PostOnly,
string OriginModule, // für die Plattform-Sperre (5.6) und das Journal
string CorrelationId);
```
Plattformspezifisches (Global: `negRisk`, Tick-Size, Decimals; US: `manualOrderIndicator`,
`synchronousExecution`) bleibt **im Adapter**. Der US-Adapter setzt `manualOrderIndicator` fest auf
`AUTOMATIC` — ein Bot, der sich als manuell ausgibt, ist ein Compliance-Fehler, keine Einstellung.
### 5.4 Konten und Zugangsdaten
- `core_accounts.platform` (Vorgabe `polymarket-global`).
- Zugangsdaten je Plattform, verschlüsselt wie F1 (`EncryptedStringConverter`):
- Global: wie heute (Wallet, Key, Secret, Passphrase, PrivateKey).
- US: Key-ID in `ApiKey`, Ed25519-Secret in `ApiSecret`. `WalletAddress`, `PrivateKey`,
`PayoutAddress` leer.
- Kalshi: Key-ID + privater Schlüssel.
Die bestehenden Felder reichen für US und Kalshi. Eine eigene Tabelle je Plattform wäre sauberer,
kostet aber eine zweite Migration der F1-Verschlüsselung. **Entscheidung: vorhandene Felder
wiederverwenden**, die Kontenansicht zeigt je Plattform nur die passenden Felder mit passender
Beschriftung. Neu prüfen, falls eine Plattform mehr als vier Geheimnisse braucht.
- Die Passwortsperre vor Konten und Geheimnissen (#567) gilt unverändert; Geheimnisse bleiben
Desktop-only (WebUI-Parität).
### 5.5 Datenbank
| Tabelle | Änderung |
|---|---|
| `core_accounts` | `+ platform` |
| `core_positions` | **keine Änderung** (Entscheidung in #623): Eine Position gehört zu einem Konto, das Konto zu genau einer Plattform. `(AccountId, IsDemo, TokenId)` bleibt eindeutig, solange `TokenId` den plattformeindeutigen `InstrumentRef.Key` hält. Eine eigene Spalte wäre eine zweite Wahrheit, die auseinanderlaufen kann |
| `core_markets` | `+ platform`; Schlüssel `(Platform, Id)` |
| Modultabellen mit Token-Bezug (`ct_`, `rf_`, `acc_`) | `+ platform` mit Vorgabe, je Modul im jeweiligen Schritt |
`Position.TokenId` bleibt, wie es ist, und hält `InstrumentRef.Key`. Die 73 Fundstellen ziehen
schrittweise um, statt in einem Commit.
Die lesenden Methoden von `IMarketRepository` (`GetById`, `FindByTokenId`, `GetActive`) liefern seit #623
nur Global-Märkte — ihre Aufrufer arbeiten mit Gamma-IDs und Token-IDs.
**Migration `AddPlatformColumns`:** Es gibt keine automatischen Migrationen beim Start. Vor dem ersten
Start einer Fassung mit #623 muss auf dem Server `dotnet ef database update --project src/PolyTrader.Core`
laufen, sonst scheitert jede Abfrage an der fehlenden Spalte `Platform`.
### 5.6 Module erklären ihre Plattformen („Auslöser")
Erweiterung von [`IPolyTraderModule`](../../../src/PolyTrader.Core/Modularity/IPolyTraderModule.cs),
abwärtskompatibel über Default-Implementierungen:
```csharp
/// Plattformen, für die dieses Modul geprüft und freigegeben ist.
/// Vorgabe: nur Polymarket Global – ein Modul, das nichts erklärt, verhält sich wie heute.
IReadOnlySet<PlatformId> SupportedPlatforms => new HashSet<PlatformId> { PlatformId.PolymarketGlobal };
/// Grund, warum das Modul eine erklärte Plattform in dieser Installation trotzdem nicht bedienen kann
/// (fehlende Fähigkeit, fehlender Schlüssel). null = bedienbar.
string? GetPlatformBlocker(PlatformId platform, PlatformCapabilities caps) => null;
```
**Eine Stelle für die Regeln.** Wie `ModuleActivationView` seit #560 liegt die Auswertung im Core
(`ModulePlatformView`), und Desktop und WebUI zeigen dasselbe:
| Wo | Was man sieht |
|---|---|
| Modul-Tab (Desktop, WebUI) | je Modul Plattform-Kennzeichen: ✓ bedienbar, ⚠ erklärt aber blockiert (mit Grund), — nicht erklärt |
| Kontenansicht | je Konto die Module, die es bedienen |
| Dashboard-Warnung | aktives Konto, das kein aktives Modul bedient; aktives Modul ohne passendes Konto |
**Wirksam an zwei Stellen:**
1. **Zuteilung:** Ein Modul bekommt nur Konten, deren Plattform es erklärt und nicht blockiert.
Module filtern nicht selbst — sie fragen den Core nach „meinen Konten".
2. **Handelspfad:** Die Registry reicht jedem Modul ein `IOrderGateway`, das `OriginModule` prüft
und eine Order für eine nicht erklärte Plattform **ablehnt und ins Journal schreibt**. Das ist die
zweite Sicherung nach dem Muster von `TradingGate` (#570): Eine Sperre, die nur in der Oberfläche
existiert, hält keinen Programmierfehler auf.
**Erste Erklärungen:**
| Modul | Global | US | Begründung |
|---|---|---|---|
| CopyTrading | ✓ | — | braucht `PublicTraderActivity`; plattformübergreifend siehe #628 |
| ResolutionFarming | ✓ | ✓ (ab #626) | nur eigene Marktdaten nötig, US-Gebühr nahe 1 sehr klein |
| Accounting | ✓ | ✓ (ab #627) | Quellen je Plattform |
| Supervisor | ✓ | ✓ | liest Journal und Dossiers, handelt nicht; `CounterfactualJob` über `IMarketCatalog` |
### 5.7 Strategieprofile je Plattform
Ein Modul, das mehrere Plattformen erklärt, hält Einstellungen **je Plattform**
(`rf_settings.platform`). Das Profil legt fest:
- Gebührenmodell (aus der Registry, nie hart kodiert) — betrifft jeden Netto-Edge-Check.
- Schwellen (Einstiegspreis, Mindest-Edge, Mindestliquidität). Bei getrenntem, kleinerem US-Pool
sind Global-Werte **nicht** übertragbar; Startwerte stammen aus der Messphase.
- Order-Stil: auf US lohnt Post-only wegen des Maker-Rabatts; auf Global zahlt der Maker 0.
- Abwicklung: Global mit Redeem, US ohne.
Die fachliche Logik (Kandidatenbewertung, Sizing, Risikogrenzen) bleibt gemeinsam und testbar ohne
Plattform.
### 5.8 Demo-Modus
Demo bleibt eine Eigenschaft des Kontos (`IsDemo`). Demo-Fills rechnen gegen **das Buch der Plattform
des Kontos**, mit deren Gebührenmodell. Da die US-Retail-API keine Sandbox hat, ist Demo gegen das
echte US-Buch der einzige Weg zur Messphase — und damit Pflicht vor dem Livegang.
---
## 6. Umsetzungsschritte
| Item | Schritt | Voraussetzung | Ergebnis |
|---|---|---|---|
| #622 | **PL-0** Voraussetzungen US-Kunde | — | KYC, API-Schlüssel, Serverstandort, Rolle geklärt |
| #623 | **PL-1** Plattform-Fundament | — | Verträge, Registry, Global-Adapter, DB-Spalten; **Verhalten unverändert** |
| #624 | **PL-2** Plattform-Erklärung der Module | #623 | Anzeige + Zuteilung + Sperre im Gateway |
| #625 | **PL-3** Adapter Polymarket US | #623; für echte Orders #622 | erst lesend, dann Demo, dann Orders |
| #626 | **PL-4** ResolutionFarming für US | #624, #625 | Profil je Plattform, Messphase |
| #627 | **PL-5** Accounting für US | #625 | US-Quellen statt Data-API/Chain |
| #628 | **PL-6** CopyTrading plattformübergreifend | #625 + Entscheidung | nicht beschlossen |
| #629 | **PL-7** Adapter Kalshi | #623 + konkreter Bedarf | nicht beschlossen |
### Akzeptanzkriterien
**PL-1**
- Alle bestehenden Tests grün, ohne Anpassung ihrer Erwartungen.
- Diff an `PolymarketClobClient.cs` ist leer. Backup trotzdem vor Beginn (Regel).
- Migration auf einer Kopie der Server-Datenbank: Bestandspositionen haben danach
`platform = polymarket-global` und denselben `OutcomeKey` wie vorher `TokenId`.
- Neue Tests: Registry löst je Plattform auf; Global-Adapter reicht Aufrufe 1:1 an den Client durch.
**PL-2**
- Ein Modul ohne Erklärung verhält sich exakt wie heute.
- Test: Order über das Gateway mit nicht erklärter Plattform → abgelehnt, Journal-Eintrag, keine
HTTP-Anfrage.
- Desktop und WebUI zeigen für dieselbe Konfiguration dieselben Kennzeichen (ein gemeinsamer Test
gegen `ModulePlatformView`).
**PL-3**
- Signatur gegen die Beispielwerte der Doku geprüft (Einheitentest mit festem Schlüssel und Zeitstempel).
- Lesend gegen Produktion: Märkte, Buch, Positionen, Saldo des Kundenkontos.
- 429 → Backoff; „Global Rate Limit Exceeded" → **kein** Drosseln (siehe Abschnitt 2).
- Secret nie im Log, nie im WebUI, verschlüsselt at-rest.
- Erste echte Order erst nach PL-4-Messphase und mit Freigabe durch Richard.
**PL-4**
- Netto-Edge-Check nutzt das US-Gebührenmodell (Test mit p = 0,50 und p = 0,97).
- Demo-Messphase mit definiertem Zeitraum und Auswertung, bevor Live freigegeben wird.
---
## 7. Ausblick Kalshi
Kalshi ist der Prüfstein für PL-1: Lässt sich der Adapter bauen, **ohne ein Modul anzufassen**, trägt
die Abstraktion. Bekannte Unterschiede (vor dem Bau gegen die aktuelle Kalshi-Doku prüfen): eigene
Anmeldung mit signierten Anfragen und privatem Schlüssel, Märkte über Ticker, Preise in Cent, eigene
Gebührenformel, eigene Demo-Umgebung. Genau deshalb ist `LimitPrice` im Vertrag eine Wahrscheinlichkeit
0..1 und die Umrechnung Sache des Adapters.
---
## 8. Offene Fragen
| Frage | Wer | Item |
|---|---|---|
| Gibt es für die Retail-API eine Testumgebung? | Anfrage an Polymarket US | #622 |
| Wo läuft die Installation des US-Kunden, und darf sie zugleich Global-Konten führen? | Richard | #622 |
| Rechtliche Einordnung unserer Rolle bei automatisiertem Handel auf einem fremden KYC-Konto | Richard / Rechtsberatung | #622 |
| Lohnt CopyTrading mit Global-Signal und US-Ausführung trotz anderer Kurse? | Entscheidung | #628 |
| Reihenfolge gegenüber Themenbereich A (Abnahme, #621 Betriebsfreigabe) | Richard | — |