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:
@@ -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
|
aber der eigentliche Prüfwert des Moduls: **Abweichungen zwischen beiden Quellen sind das
|
||||||
Signal.**
|
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
|
## 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)
|
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
|
## T — Technische Schuld
|
||||||
|
|||||||
@@ -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-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-Supervisor.md` | S-0–S-4 ✅, Live-Key-Test ist **B5** |
|
||||||
| `KONZEPT-Modul-DataDriven.md` | **D1** — nicht beschlossen, es gibt keinen Umsetzungsplan |
|
| `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
|
### 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 | — |
|
||||||
Reference in New Issue
Block a user