diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 3309870..dfa0150 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -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 diff --git a/docs/archiv/README.md b/docs/archiv/README.md index b000822..7c678fc 100644 --- a/docs/archiv/README.md +++ b/docs/archiv/README.md @@ -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 diff --git a/docs/archiv/konzepte/KONZEPT-Multi-Plattform.md b/docs/archiv/konzepte/KONZEPT-Multi-Plattform.md new file mode 100644 index 0000000..726fbce --- /dev/null +++ b/docs/archiv/konzepte/KONZEPT-Multi-Plattform.md @@ -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, + 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 Available { get; } + PlatformCapabilities Capabilities(PlatformId p); + T Get(PlatformId p) where T : class; // wirft, wenn Plattform den Vertrag nicht hat + bool TryGet(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 SupportedPlatforms => new HashSet { 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 | — |