- DbContextModelTests: feinkörnige Modell-Invarianten - Dezimal-Präzision (18,6) auf Geldfeldern (Core + Settings), MaxLength auf Strings, manuell gesetzte Keys (ValueGeneratedNever), AssignedAccountIds hat Value-Converter + text-Spalte, MarketData JSON-Spalten = text, Indizes (TradeRecord.ClosedAt, MasterTraderHistory TraderId/ClosedAt). (GetColumnType() wirft unter InMemory -> Spaltentyp via Relational:ColumnType- Annotation ausgelesen.) - MongoExportParserTests erweitert: numerische statt String-Dezimale, unbekannte Felder ignoriert, mehrere Dokumente in Reihenfolge, AssignedAccountIds als String-Zahlen, IsActive-Default. - RepositoryEdgeCaseTests: GetAll leer != null, Update-Alias, Factory-Isolation, History-Exists/GetByTraderSince inklusive an den Grenzen. Alle 78 gruen. (Copytrading-Service-Logik bewusst noch nicht getestet - wird parallel ueberarbeitet.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.6 KiB
Umsetzungsplan: Modul „MarketMaking" (Liquidity Rewards + Spread)
Stand: 2026-07-06 Ziel: Neues Strategiemodul, das beidseitige Limit-Orders in belohnungs- berechtigten Polymarket-Märkten stellt und drei Ertragsquellen kombiniert: tägliche Liquidity Rewards (USDC), Maker-Rebates und den Spread selbst. Reihenfolge: Nach ResolutionFarming. Harte Voraussetzung: Phase 1 (Marktdaten-Fundament:
ClobMarketDataService,ClobUserChannelService) ausUMSETZUNGSPLAN-CopyTrading-Verbesserungen.md.
0. Strategie-Hintergrund
Polymarket zahlt täglich (00:00 UTC) USDC-Rewards an Wallets, die kompetitive Resting-Limit-Orders in berechtigten Märkten stellen. Der Reward-Pool liegt 2026 bei > $5 M/Monat (Sport-Peaks ~$8 M). Die Formel belohnt: Nähe zum Midpoint (innerhalb eines markt-spezifischen Max-Spreads), Ordergröße (Mindestgröße je Markt) und beidseitige Tiefe (einseitige Orders scoren reduziert). Seit den Taker-Fees (März 2026) gibt es zusätzlich ein Maker-Rebate-Programm (Anteil der Taker-Fees wird täglich an Maker ausgeschüttet). Maker zahlen selbst keine Fees.
Referenzen (bei Umsetzung Formel/Parameter aktuell verifizieren):
- https://docs.polymarket.com/market-makers/liquidity-rewards
- https://docs.polymarket.com/trading/fees (Maker-Rebates)
- Reward-Parameter je Markt (Max-Spread, Min-Size, Tages-Pool) kommen aus der Gamma-/CLOB-API am Markt-Objekt.
Warum dieses Modul strategisch wertvoll ist: Es ist die einzige Strategie, bei der wir nicht gegen schnellere Bots um denselben Trade konkurrieren — Anwesenheit wird bezahlt. Ertrag ist stetig statt direktional.
Hauptrisiko: Adverse Selection. Unsere Quotes werden bevorzugt dann gefüllt, wenn jemand mit besserer Information (News-Bot, Live-Sport-Feed) gegen uns handelt. Gegenmaßnahmen: Marktauswahl (ruhige, langlaufende Märkte; anfangs KEINE Live-Sport- und KEINE Krypto-Kurzfrist-Märkte), Inventar-Limits, Volatilitäts-Pause.
1. Architektur-Einbettung
Neues Projekt src/PolyTrader.Modules.MarketMaking/ als IPolyTraderModule
(Name = "MarketMaking", DbPrefix = "mm_"), Registrierung in Program.cs.
Eigener Polymarket-Account zwingend (gleiche Begründung wie im
ResolutionFarming-Plan, hier noch kritischer: Der Copytrading-
TraderMonitorService würde MM-Inventar als Positionen adoptieren und der
Copytrading-CancelConflictingOrdersAsync-Mechanismus würde unsere
Resting-Quotes canceln!).
Persistenz
| Tabelle | Inhalt |
|---|---|
mm_settings |
Globale + je-Markt-Settings (Size, Spread-Ziel, Limits) |
mm_markets |
Kuratierte/gescorte Märkte (Reward-Parameter, Status) |
mm_quotes_log |
Quote-Historie (Preis, Size, Dauer, Cancel-Grund) — für Reward-Optimierung |
mm_fills |
Fills mit Seite, Preis, Inventar danach |
mm_daily_pnl |
Tagesabrechnung: Rewards, Rebates, Spread-PnL, Inventar-PnL |
2. Komponenten
2.1 MarketSelectorJob — Marktauswahl & Scoring
Täglich + manuell triggerbar:
- Reward-berechtigte Märkte über Gamma-/CLOB-API listen (Felder: Reward-Pool/
Rate,
rewardsMaxSpread,rewardsMinSize— Feldnamen verifizieren). - Score je Markt:
erwarteter Reward pro gequoteter $ ÷ Risiko-Proxy.- Reward-Schätzung: Tages-Pool des Markts ÷ beobachtete konkurrierende Maker-Liquidität innerhalb des Max-Spreads (aus Orderbuch-Snapshots).
- Risiko-Proxy: realisierte Midpoint-Volatilität (Stddev der Mid-Bewegungen
über 24 h aus
ClobMarketDataService-Daten), Zeit bis Resolution (je näher, desto gefährlicher), Kategorie.
- Harte Ausschlüsse (erste Ausbaustufe): Live-Sport (in-play), Krypto- Kurzfrist-Märkte (15 min/1 h), Märkte < 7 Tage vor EndDate, Midpoint außerhalb 0.10–0.90 (Extrempreise = asymmetrisches Inventarrisiko).
- Output: Ranking in
mm_markets+ UI; Betreiber aktiviert Märkte manuell (Whitelist-Prinzip — der Bot wählt in v1 nicht selbst).
2.2 QuotingEngine : BackgroundService — Kern des Moduls
Je aktivem Markt eine Quote-State-Machine:
- Zielquote: Bid und Ask symmetrisch um den Midpoint, Abstand
QuoteSpreadTicks(Setting), immer innerhalb des Reward-Max-Spreads; Size ≥ Reward-Min-Size (SettingQuoteSizeUsd, initial klein). - Requote-Trigger: Midpoint-Bewegung > Schwelle (z. B. 1 Tick), eigene
Order gefüllt, Reward-Fenster verletzt. Requote = Cancel + neue Order über
PolymarketClobClient. - Churn-Begrenzung: Mindest-Ruhezeit zwischen Requotes (z. B. 3–5 s), Hysterese (nicht bei jedem Tick nachziehen) — API-Rate-Limits und Order-Spam vermeiden.
- Fill-Verarbeitung: über
ClobUserChannelService(Echtzeit). Nach Fill: Inventar aktualisieren, Gegenquote anpassen (siehe 2.3). - Alle Quotes/Cancels in
mm_quotes_log(Grundlage für Optimierung).
Die Preis-/Requote-Logik als pure, getestete Klasse (QuoteCalculator)
implementieren — Input: Book-Snapshot, Inventar, Settings; Output: Ziel-Quotes.
Unit-Tests in PolyTrader.Tests (das ist die kritischste Logik des Moduls).
2.3 InventoryManager — Risikosteuerung
- Inventar je Markt = Netto-Shares (YES-äquivalent) × Preis.
- Skew: Bei wachsendem Inventar Quotes asymmetrisch verschieben
(Kaufseite weiter weg, Verkaufsseite näher/attraktiver), Faktor
proportional zu
Inventar / MaxInventoryUsd. - Limits (Settings je Markt + global):
MaxInventoryUsdje Markt (Default klein, z. B. 50).MaxTotalInventoryUsdüber alle Märkte.- Bei Limit-Bruch: Quoting nur noch auf der abbauenden Seite („Reduce-Only-Modus") bis Inventar < 50 % des Limits.
- Exit vor Resolution: Ab
ExitHoursBeforeEnd(Default 48 h) Reduce-Only, ab 24 h aktiver Abbau (Maker-seitig, notfalls Taker mit Verlust-Deckel). - Volatilitäts-Pause: Midpoint-Sprung > X % in Y Sekunden → alle Quotes
des Markts canceln, Cooldown Z Minuten (News-Schutz). Global-Kill-Switch
analog
GlobalTradingPaused.
2.4 RewardTracker
- Tägliche Reward-/Rebate-Eingänge erkennen (USDC-Transfers auf die Wallet
via Data-API/Alchemy) und
mm_daily_pnlzuordnen. - Tagesabrechnung:
Rewards + Rebates + SpreadPnL + InventarPnL(mark-to-mid) − Verluste = Netto. Threema-Tagesreport. - Kennzahl je Markt: Reward-ROI pro gequoteter $ → Feedback in den
MarketSelectorJob(schlechte Märkte deaktivieren).
2.5 UI
- Tab „Märkte": Kandidaten-Ranking, aktiv/inaktiv-Toggle, Reward-Parameter.
- Tab „Live": aktuelle Quotes, Inventar je Markt (Ampel), letzte Fills.
- Tab „Abrechnung":
mm_daily_pnl-Historie, Reward-ROI je Markt. - Tab „Settings": PropertyGrid.
3. Phasen & Akzeptanzkriterien
Phase MM-1: Fundament-Verifikation + Selector (read-only)
- Voraussetzung prüfen:
ClobMarketDataService/ClobUserChannelServicelaufen stabil (mehrtägiger Soak-Test, Reconnect-Verhalten). MarketSelectorJob+ UI-Ranking, keine Orders.- Akzeptanz: Ranking plausibel; Orderbuch-Daten für Top-Märkte lückenlos über 72 h (Basis für Volatilitäts-Proxy).
Phase MM-2: Paper-Quoting (Messung Adverse Selection)
- QuotingEngine läuft vollständig, sendet aber keine Orders; simulierte Fills: Quote gilt als gefüllt, wenn der Marktpreis durch unser Quote-Level handelt (aus Market-Channel-Trades ableitbar).
- 2 Wochen laufen lassen. Messen: simulierter Spread-PnL, Inventarverläufe, Wie oft wären wir „überfahren" worden (Fill unmittelbar vor großer Gegenbewegung)?
- Akzeptanz/Go-Kriterium: simuliertes Inventar bleibt innerhalb der Limits; Spread-PnL ≥ 0 (Rewards kommen on top und sind der eigentliche Ertrag).
- Hinweis: Rewards selbst lassen sich nicht simulieren — sie erfordern echte Resting-Orders. Paper-Phase misst nur die Risikoseite.
Phase MM-3: Live auf 1–2 ruhigen Märkten
- Eigener Account, kleines Kapital (z. B. 300–500 USDC),
QuoteSizeUsdknapp über Reward-Min-Size, 1–2 langlaufende Politik-/Geopolitik-Märkte. - Akzeptanz nach 2–4 Wochen: tägliche Rewards fließen nachweislich
(
mm_daily_pnl); Netto (Rewards + Spread − Inventarverluste) > 0; keine Order-Leichen (Cancel-Fehler) im CLOB.
Phase MM-4: Skalierung + Skew-Feintuning
- Mehr Märkte (Selector-getrieben), Inventar-Skew-Parameter aus Fill-Daten optimieren, Size je Markt anhand Reward-ROI erhöhen.
Phase MM-5 (optional): Reward-Optimierung
- Order-Laddering (mehrere Level innerhalb des Max-Spreads), dynamische Spread-Wahl abhängig von Konkurrenz-Liquidität, Teilnahme an Sponsor-/Sonder-Reward-Programmen (z. B. Sport-Events pre-game).
4. Risiken & Gegenmaßnahmen
| Risiko | Gegenmaßnahme |
|---|---|
| Adverse Selection durch News-/Latenz-Bots | Marktauswahl (keine Live-Events), Volatilitäts-Pause, kleine Size |
| Inventar läuft in Resolution | Exit-Regeln ab 48 h/24 h vor EndDate (2.3) |
| Order-Churn → Rate-Limits/Sperren | Requote-Hysterese, Mindest-Ruhezeit, Monitoring der API-Fehlerquote |
| Reward-Regeländerungen | Parameter täglich aus API lesen, nichts hartkodieren |
| WSS-Ausfall → blinde Quotes | Watchdog: keine Book-Updates > N s → alle Quotes canceln (Fail-Safe) |
| Konflikt mit Copytrading | Eigener Account (Abschnitt 1) |
Der Fail-Safe „bei Datenverlust alles canceln" ist Pflicht ab MM-3 und muss getestet werden (WSS künstlich trennen).
5. Offene Entscheidungen
- Startmärkte (Empfehlung: 1–2 langlaufende Politik-/Geopolitik-Märkte mit mittlerem Volumen — genug Reward-Pool, wenig Newsflow).
QuoteSizeUsd/Kapital für MM-3.- Beidseitig quoten von Anfang an (voller Reward-Score) oder zunächst einseitig konservativ? (Empfehlung: beidseitig, dafür kleine Size — einseitig scored schlechter und halbiert den Lerneffekt.)