Docs: Konzepte/Plaene in docs/ mit Typ-Unterordnern buendeln

Root aufgeraeumt: alle Konzept-/Plan-/Fach-Dokumente nach docs/ verschoben,
organisiert nach Typ (wie fuer ein separates Docs-Repo vorgeschlagen, aber bewusst
in diesem Repo, damit Plan->umsetzende-Commits nachvollziehbar bleiben):
- docs/konzepte/       (KONZEPT-*)
- docs/umsetzungsplaene/ (UMSETZUNGSPLAN-*)
- docs/ideen/          (fruehe Ideen, Platzhalter)
- docs/pruefplaene/    (PRUEFPLAN-*)
- docs/steuer/         (Steuer-/Buchhaltungs-Doks, z.B. US-CPA-Fragebogen)
- docs/README.md       (Index/Konventionen)

Getrackte Plaene als Rename verschoben (History erhalten); zuvor untracked Konzept-/
Plan-Dateien jetzt versioniert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-14 10:15:08 +02:00
co-authored by Claude Opus 4.8
parent 1c3a364df2
commit c5f0b1d188
15 changed files with 1004 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
# Doku (Predictalytics / PolyTraderSharp)
Zentrale Ablage für Konzepte, Umsetzungspläne, Ideen und Fach-/Business-Dokumente — nach Typ in
Unterordnern organisiert. Code-gekoppelte Umsetzungspläne bleiben bewusst in **diesem** Repo (statt in
einem separaten Docs-Repo), damit „Plan → umsetzende Commits" nachvollziehbar bleibt.
## Struktur
- **`konzepte/`** — Konzepte für neue Module/Features (das „Warum" und „Was", vor der Umsetzung).
- `KONZEPT-Modul-Accounting.md` — Buchhaltungs-/Steuer-Reporting-Modul (unabhängiger Polymarket-Abruf, BWA, CSV/PDF, US-Steuer Florida LLC).
- `KONZEPT-Modul-DataDriven.md`
- **`umsetzungsplaene/`** — konkrete, slice-weise Implementationspläne (das „Wie"), oft mit `file:line`-Bezügen und Fortschritt.
- `UMSETZUNGSPLAN-Modularisierung.md` — Umbau Copytrader → Core + Module.
- `UMSETZUNGSPLAN-CopyTrading-Verbesserungen.md` — Rentabilitäts-/Fable-Plan Copytrading.
- `UMSETZUNGSPLAN-Fable-Review-Fixes.md` — Fable-Code-Review-Fixes (Slices 06 + Tests).
- `UMSETZUNGSPLAN-Modul-ResolutionFarming.md` — Strategiemodul ResolutionFarming.
- `UMSETZUNGSPLAN-Modul-MarketMaking.md` — Strategiemodul MarketMaking (Phase-1-blockiert).
- `UMSETZUNGSPLAN-Modul-BundleArbitrage.md` — Strategiemodul BundleArbitrage (Phase-1-blockiert).
- `UMSETZUNGSPLAN-AutoRedeem.md`, `UMSETZUNGSPLAN-AI-Aufloesequalitaet.md`, `UMSETZUNGSPLAN-StrategieDrift.md`
- **`ideen/`** — frühe Ideen/Explorationen, bevor sie zu einem Konzept oder Umsetzungsplan reifen.
- **`pruefplaene/`** — Prüf-/Validierungspläne.
- `PREDICTALYTICS-PRUEFPLAN-Master-Auswahl.md` — Master-Trader-Auswahl (separates Predictalytics-Projekt).
- **`steuer/`** — Steuer-/Buchhaltungs-Fachdokumente & Vorlagen (auch zum Weitergeben an Berater).
- `Accounting-US-Tax-Questionnaire.md` — Fragebogen (EN) für die US-Steuerberaterin (Florida LLC).
## Konventionen
- Neue Konzepte: `KONZEPT-*.md``konzepte/`. Neue Umsetzungspläne: `UMSETZUNGSPLAN-*.md``umsetzungsplaene/`.
- Übergreifende/an Externe weitergebbare Dokumente können später in ein eigenes `Predictalytics-Docs`-Repo
ausgelagert werden (Ordner rausziehen genügt) — für jetzt bewusst hier gebündelt.
+1
View File
@@ -0,0 +1 @@
Platzhalter hier kommen frühe Ideen/Explorationen rein, bevor sie zu einem Konzept oder Umsetzungsplan werden.
+255
View File
@@ -0,0 +1,255 @@
# Konzept: Modul „Accounting" (Steuer-/Buchhaltungs-Reporting aller Live-Accounts)
> Stand: 2026-07-14
> Ziel: Vollständige, **unabhängig von unserer Trading-DB** erhobene, buchhalterisch korrekte
> Erfassung ALLER Transaktionen aller Live-Polymarket-Accounts. Periodische (meist monatliche),
> vor einer Steuerbehörde nachvollziehbare Abrechnungen — je einzelnem Account ODER über alle
> Accounts, für frei wählbare Zeiträume. BWA-artige Kennzahlen-Übersicht in der UI. Export als
> CSV und PDF.
> Reihenfolge: unabhängig, jederzeit baubar (kein Live-Trading nötig — rein lesende API-Abrufe).
> **Kein Handel; reines Ingest-/Reporting-Modul.**
>
> **Entscheidungen Richard (2026-07-14):**
> - Währung: **USDC nativ + USD + EUR** (jede Transaktion in allen drei ausgewiesen).
> - Abrechnung: neutrale prüfbare Aufstellung **UND** konkrete **US-Steuerberechnung** — Zielland
> **USA, Florida LLC** (Florida ohne State Income Tax → nur Federal). Als dokumentierte, vom CPA
> prüfbare Rechenschicht, **nicht als Steuerberatung** (Disclaimer, §4a).
> - Umfang v1: **inkl. On-Chain-Ein-/Auszahlungen** von Anfang an (vollständige Kapitalsicht).
---
## 0. Leitprinzipien
1. **Unabhängige Quelle = Polymarket, NICHT unsere DB.** Das Modul erhebt die Buchungsgrundlage
ausschließlich über eigene, regelmäßige Abrufe direkt bei Polymarket und speichert sie roh +
normalisiert in eigenen Tabellen. Unsere eigenen Trade-Logs (Copytrading/ResolutionFarming/Core)
werden **nur** für den optionalen Abgleich (§7) herangezogen, **nie** als Buchungsgrundlage.
2. **Nachvollziehbarkeit / Audit.** Jeder Buchungssatz führt auf einen konkreten, prüfbaren Nachweis
zurück (Transaktions-Hash, Activity-/Trade-ID, Abruf-Zeitpunkt, Rohdaten-Snapshot). Der Roh-Ingest
ist **unveränderlich (append-only)**; Abrechnungen sind daraus **reproduzierbar** ableitbar.
3. **Zwei Ebenen: neutraler Ledger + prüfbare US-Steuerschicht.** Unten liegt eine vollständige,
länderneutrale Transaktions-/Ledger-Aufstellung + Kennzahlen (belastbare Basis). Darauf setzt eine
**konfigurierbare, dokumentierte US-Steuer-Rechenschicht** (Florida LLC, §4a) — mit klaren, im
Export ausgewiesenen Annahmen, **die der US-CPA prüft/bestätigt**. Das Tool rechnet; es berät nicht
(Disclaimer, §4a). Der neutrale Ledger bleibt auch bei anderer steuerlicher Einordnung gültig.
4. **Lesend / idempotent.** Keine Orders, keine On-Chain-Writes. Überlappende Wiederholungs-Abrufe
dürfen **nichts doppelt buchen** (stabile Idempotenz-Schlüssel, Upsert statt Insert).
---
## 1. Architektur-Einbettung
Neues Projekt `src/PolyTrader.Modules.Accounting/` als `IPolyTraderModule`
(`Name = "Accounting"`, `DbPrefix = "acc_"`), Registrierung in `Program.cs`. Referenziert nur den
Core. Eigener `AccountingDbContext` (acc_-Tabellen), eigene UI (ein Fenster mit Tabs), eigene
Settings-Sektion.
- Nutzt den bestehenden `PolymarketApiService` (Data-API `/activity`, `/positions`,
`GetUsdcBalanceAsync(wallet)`) und für On-Chain-Ein-/Auszahlungen die vorhandene Alchemy-Anbindung.
- Betrifft ALLE Live-Accounts (aus `TradingState.Accounts` bzw. `IAccountRepository`; `!IsDemo`,
mit gesetzter `WalletAddress`).
- **Hinweis Ist-Stand:** `PolymarketApiService.GetTraderActivityAsync` filtert heute hart auf
`type=TRADE`. Fürs Accounting brauchen wir ALLE Activity-Typen → entweder den Filter parametrisieren
oder eine eigene, accounting-spezifische Abruf-Methode (schlanker, ohne Copytrading-Annahmen).
---
## 2. Datenbeschaffung (der Kern: der unabhängige Abruf)
### 2.1 Ledger-Quellen bei Polymarket
- **Data-API `/activity?user=<wallet>`** = primäres Kontobuch. Enthält (Feldnamen/Typen bei Umsetzung
zwingend aus https://docs.polymarket.com verifizieren) u. a.:
- `TRADE` (BUY/SELL-Fills): Preis, Size, USDC, Fee, Token/Market, txHash, Timestamp, Side.
- `REDEEM` (Resolution-Auszahlung: Gewinner-Shares → USDC).
- `SPLIT` / `MERGE` / `CONVERSION` (CTF-/NegRisk-Operationen; meist geldneutral, aber bestandsrelevant).
- `REWARD` (Liquidity Rewards) / Maker-Rebates — Einnahmen.
- **On-Chain USDC-Ein-/Auszahlungen** (Deposits/Withdrawals ins/aus dem Wallet): sind **nicht** Teil
der Trading-Activity. Quelle: Polygon/Alchemy (ERC-20-Transfer-Logs USDC ↔ Wallet).
- **Adresse ist vorhanden:** Polymarket nutzt **Gnosis-Safe-Proxy-Wallets** — genau die Adresse, die
wir bereits als `AccountState.WalletAddress` für Balance- und Activity-Abrufe verwenden. Sie ist
also die Watch-Adresse für USDC-Transfers (keine zusätzliche Beschaffung nötig).
- **Die eigentliche Arbeit ist die Klassifikation:** Die USDC-Transfers des Safes enthalten SOWOHL
trading-interne Bewegungen (Safe ↔ Polymarket-Contracts: CTF/Exchange/NegRisk — bereits in `/activity`
als Trades/Redeems erfasst) ALS AUCH echte Ein-/Auszahlungen (Safe ↔ EXTERNE Adressen). Nur letztere
sind Deposits/Withdrawals. Klassifikation über eine **Whitelist der Polymarket-System-Contracts**
(die CTF-Adresse `0x4D97…6045` liegt bereits im Code — Exchange/NegRisk-Adapter/USDC ergänzen, aus
docs verifizieren). Alternativ als Kreuzprobe: ΔSafe-Balance Σ(interne Activity) = externe Netto-Ein-/Auszahlung.
- ⚠️ Gnosis-Safe-Nuance: Transfers laufen ggf. als Safe-`execTransaction`; die ERC-20-Transfer-Logs
(from/to = Safe) bleiben aber die maßgebliche, prüfbare Quelle.
- **Balance-Anker**: `GetUsdcBalanceAsync(wallet)` je Abruf als Kontrollpunkt (End-Saldo Soll-Ist).
### 2.2 Vollständigkeit & Idempotenz
- **Backfill + Inkrementell**: Erstlauf lädt die volle Historie je Account (paginiert, `offset`/`limit`;
Rate-Limits beachten — Activity 1000/10 s, Positions 150/10 s, bereits im ApiService limitiert).
Danach nur neue Ereignisse ab dem letzten bekannten Zeitpunkt, mit Sicherheits-**Lookback-Überlappung**
gegen API-Lag.
- **Idempotenz-Schlüssel** je Buchungssatz: stabile Kombination `txHash + logIndex/assetId + type`
→ überlappende Abrufe buchen nicht doppelt (Unique-Constraint + Upsert).
- **Lückenerkennung**: Timestamp-Kontinuität + Seiten-Vollständigkeit prüfen; fehlende Bereiche gezielt
nachladen und markieren.
- **Rohdaten-Snapshot**: die JSON-Rohantwort je Abruf-Batch speichern (Nachweis + Reproduzierbarkeit),
zusätzlich zu den normalisierten Sätzen.
### 2.3 Abruf-Steuerung
- `AccountingIngestJob : BackgroundService` (JobManager-registriert, manuell triggerbar), Intervall
konfigurierbar (z. B. stündlich inkrementell, täglich Voll-Reconcile). Nutzt die bestehenden
Rate-Limiter des `PolymarketApiService`.
---
## 3. Persistenz (acc_-Tabellen, append-only Ledger)
| Tabelle | Inhalt |
|---|---|
| `acc_ledger` | Normalisierte, **unveränderliche** Buchungssätze: AccountId, EventType (TRADE_BUY/TRADE_SELL/REDEEM/REWARD/FEE/SPLIT/MERGE/DEPOSIT/WITHDRAWAL), Timestamp, TokenId/Market, Outcome, Size, PriceUsdc, GrossUsdc, FeeUsdc, NetUsdc, TxHash, LogIndex, Source, IngestBatchId, **IdempotencyKey (unique)** |
| `acc_ingest_runs` | Abruf-Protokoll: AccountId, Von/Bis, Start/Ende, #Sätze, Ok/Fehler, Balance-Anker (Soll-Ist) |
| `acc_raw` | Rohdaten-Snapshots (JSON) je Batch (Nachweis) |
| `acc_fx_rates` | (falls Fiat, §10.1) amtliche Tages-FX-Kurse (z. B. USD→EUR) je Datum |
| `acc_statements` (optional) | Erzeugte Periodenabrechnungen (Metadaten + Daten-Hash) für Versionierung/Reproduzierbarkeit |
Autoincrement-PKs (Lehre aus dem CopyTrading-`TradeId`-Problem), Unique-Index auf `IdempotencyKey`,
Indizes auf `(AccountId, Timestamp)`.
---
## 4. Buchhaltungs-Logik (pure, testbar) — `AccountingEngine`
Wie bei den anderen Modulen liegt die geldkritische Logik pur und unit-getestet in `Logic/`:
- **Klassifikation** roher Activity → Buchungssatz-Typ + Vorzeichen (Einnahme/Ausgabe). Rein/testbar.
- **Periodenabrechnung** (Zeitraum × Account bzw. alle): aggregiert die Ledger-Sätze zu:
Anfangssaldo, Einlagen, Entnahmen, Handelsvolumen, realisierte Gewinne/Verluste, Fees, Rewards,
Netto-Ergebnis, Endsaldo — mit **Soll-Ist gegen den Balance-Anker** (Abweichung = Vollständigkeits-Signal).
- **Realisierung / Kostenbasis**: Gewinn/Verlust wird bei SELL/REDEEM realisiert; Kostenbasis je
Position per **FIFO** (US-Norm für Krypto/Property; Specific-ID als Option, §10.5) — Lot-Matching der
BUYs zu jeder Veräußerung, inkl. Haltefristen (short/long term). Pure/testbar. Offene Positionen zum
Periodenende optional als **Mark-to-Market** ausweisen, aber getrennt vom realisierten Ergebnis.
- **Währung/FX**: jede Transaktion in **USDC (nativ), USD und EUR**. Umrechnung je Transaktionsdatum:
USDC→USD (Stablecoin, Annahme 1:1 als USD-Äquivalent — im Export dokumentiert; realer USDC/USD-Kurs
optional) und USD→EUR über amtliche Tageskurse (EZB), versioniert in `acc_fx_rates`.
---
## 4a. US-Steuer-Rechenschicht (Florida LLC) — konfigurierbar, CPA-prüfbar
> ⚠️ **Kein Steuerrat.** Diese Schicht rechnet Zahlen nach **dokumentierten, konfigurierbaren
> Annahmen** aus und weist diese im Export offen aus. Die steuerliche Einordnung von
> Prediction-Market-/Event-Contract-Erträgen in den USA ist **nicht eindeutig geklärt**. Der Output
> ist zur **Prüfung/Bestätigung durch einen US-CPA/Steuerberater** gedacht, nicht als endgültige
> Steuererklärung. Jede Annahme ist im PDF/CSV dokumentiert und in den Settings umstellbar.
**Rahmen (Defaults, alle in Settings umstellbar):**
- **Entität:** Florida LLC. Florida erhebt **keine State Income Tax** → nur **Federal**. LLC-Typ
(single-member = disregarded → Schedule C/D im 1040; vs. multi-member = Partnership 1065 + K-1)
bestimmt nur die Ziel-Formulare, **nicht** die Gewinnermittlung (§10.7).
- **Einordnung (Default-Annahme):** jede Position = **Property-Disposition** → realisierter Gewinn/
Verlust je Veräußerung (SELL/REDEEM) im **Form-8949/Schedule-D-Stil**: Proceeds (USD), Cost Basis
(USD), Holding Period (short/long), Gain/Loss. Alternative Einordnungen (ordinary income, gambling,
§1256) als umstellbare Annahme vorgesehen — Auswahl trifft der CPA (§10.4).
- **USDC:** als **USD-Äquivalent (1:1)** behandelt; USDC-Käufe/-Verkäufe gelten nicht separat als
steuerbares Krypto-Event (dokumentierte Vereinfachung; abschaltbar).
- **Kostenbasis:** **FIFO** (Default) oder Specific-ID; Lot-genau, mit Haltefristen.
- **Wash-Sale:** Default-Annahme „nicht anwendbar" auf Event-Contracts/Krypto (Stand 2026) — als
Schalter, da Rechtslage im Fluss.
**Output der Steuerschicht:**
- **Form-8949-artige Veräußerungsliste** je Account/Zeitraum (Description, Acquired, Sold, Proceeds,
Cost Basis, Gain/Loss, Short/Long) — CSV + PDF.
- **Schedule-D-artige Zusammenfassung** (kurz-/langfristig, Summen) je Account und aggregiert über die LLC.
- Vollständige **Methodik-/Annahmen-Seite** im Export (Reproduzierbarkeit + Prüfbarkeit).
Die Rechenlogik (FIFO-Lot-Matching, Haltefrist, Gain/Loss, FX-Umrechnung je Datum) liegt **pur und
unit-getestet** in `Logic/` (z. B. `UsTaxEngine`), getrennt vom neutralen Ledger.
---
## 5. UI (WinForms, ein Fenster mit Tabs — Muster wie ResolutionFarming)
- **Übersicht / BWA**: Kennzahlen-Kacheln für den gewählten Zeitraum + Account(s): Netto-Ergebnis,
Handelsvolumen, Fees, Rewards, Einlagen/Entnahmen, Endsaldo, realisiert vs. offen; Monats-/Perioden-Vergleich.
- **Ledger**: filterbare Transaktionsliste inkl. Nachweisspalten (txHash etc.).
- **Steuer (US)**: Form-8949-artige Veräußerungsliste + Schedule-D-Zusammenfassung je Account/alle,
mit ausgewiesenen Annahmen (FIFO, Einordnung, USDC=USD). Werte in USD (und EUR).
- **Abrechnungen / Export**: Zeitraum-Picker (Monats-Presets + frei), Account-Auswahl (einzeln / alle),
Währungswahl (USDC/USD/EUR), Buttons „CSV" und „PDF".
- **Abruf / Status**: Ingest-Läufe, Vollständigkeits-/Lücken-Status, Balance-Soll-Ist, manueller Trigger.
---
## 6. Export (CSV + PDF)
- **CSV**: vollständiger Ledger + Aggregat je Abrechnung (maschinen-/prüfbar).
- **PDF**: formatierte Abrechnung — Kopf (Account, Wallet, Zeitraum, Erstellungsdatum), Aggregat-Tabelle,
Transaktionsliste, Methodik-/Nachweis-Hinweis. Library **PDFsharp/MigraDoc (MIT)** — echte,
bedingungslose MIT-Lizenz ohne Umsatzschwelle; MigraDoc eignet sich für tabellarische
Abrechnungen/Berichte. (QuestPDF bewusst NICHT: dessen „Community"-Lizenz ist kostenlos nur unter
1 Mio USD Jahresumsatz — für eine handelnde LLC ein Lizenzrisiko. Siehe §10.1.)
- **Reproduzierbarkeit**: jeder Export trägt Zeitraum, Datenstand (letzter Ingest), Zeilenzahl und einen
Daten-Hash → gleiche Eingabe ⇒ identische Abrechnung (wichtig für die Prüfbarkeit).
---
## 7. Abgleich mit eigener Trade-DB (niedrige Priorität)
Gegenüberstellung Polymarket-Ledger ↔ unsere Modul-/Core-Trade-Logs je Account/Zeitraum: fehlende/
zusätzliche Trades, Preis-/Size-/Fee-Abweichungen, PnL-Differenzen. Rein analytisch — findet
Sync-/Buchungsfehler unserer Trading-Seite. Bericht in der UI + Export.
---
## 8. Phasen & Akzeptanzkriterien
- **A-1 Ingest (read-only), inkl. Ein-/Auszahlungen:** Modul + acc_-Persistenz + Activity-Ingest
(ALLE Typen) + On-Chain-USDC-Deposits/Withdrawals + Backfill/Inkrement + Idempotenz + Ingest-Status-UI.
**Akzeptanz:** volle Historie eines Live-Accounts vollständig & doppelfrei; Balance-Anker Soll-Ist ≈ 0
(inkl. Ein-/Auszahlungen).
- **A-2 Abrechnung + Übersicht + FX:** `AccountingEngine` + BWA-UI + Periodenabrechnung je Account/alle,
Werte in USDC/USD/EUR (Tageskurse in `acc_fx_rates`). **Akzeptanz:** Monatsabrechnung stimmt gegen
Balance-Anker; Kennzahlen plausibel; FX nachvollziehbar.
- **A-3 US-Steuerschicht:** `UsTaxEngine` (FIFO-Lot-Matching, Haltefristen, Gain/Loss) + Form-8949-/
Schedule-D-Ansicht + Annahmen-Dokumentation. **Akzeptanz:** Summe realisierter Gain/Loss stimmt gegen
die neutrale Abrechnung; Annahmen ausgewiesen.
- **A-4 Export:** CSV + PDF (Abrechnung, Ledger, Form-8949/Schedule-D) mit Zeitraum-/Account-/Währungswahl.
**Akzeptanz:** vollständig, reproduzierbar, prüfbar.
- **A-5 Reconciliation (niedrig):** Abgleich mit eigener DB.
Die geldkritische Logik (Klassifikation, Aggregation, Realisierung, FX) ist von Anfang an pur +
unit-getestet; Ingest/Export werden über Interfaces (Activity-Quelle, PDF-Writer) testbar gehalten —
wie bei ResolutionFarming die Live-Anbindung hinter Interfaces liegt.
---
## 9. Risiken & Gegenmaßnahmen
| Risiko | Gegenmaßnahme |
|---|---|
| Unvollständige API-Historie / Pagination-Lücken | Balance-Anker-Soll-Ist als Vollständigkeits-Wächter; Lückenerkennung + Nachlad; Rohdaten-Snapshots |
| API-Feld-/Endpoint-Änderungen | Rohdaten speichern; Normalisierung entkoppelt; Feldnamen bei Umsetzung aus docs verifizieren |
| Doppelbuchung bei überlappenden Abrufen | strikte Idempotenz-Schlüssel + Upsert |
| Steuerliche Fehlinterpretation | bewusst neutrale, vollständige Aufstellung statt Steuerberechnung; Methodik im Export dokumentiert |
| FX-Korrektheit | amtliche Tageskurse (z. B. EZB) versioniert in `acc_fx_rates` |
| Falsche Wallet-Adresse (Proxy vs. Signer) für Deposits | Adress-/Transfer-Semantik je Account verifizieren |
---
## 10. Entscheidungen & offene Punkte
**Entschieden (2026-07-14):**
-**Währung:** USDC nativ + USD + EUR (Tageskurse EZB, USDC≈USD dokumentiert).
-**Abrechnung:** neutraler Ledger **+** US-Steuerschicht (Florida LLC), als CPA-prüfbare Rechenschicht.
-**Umfang v1:** inkl. On-Chain-Ein-/Auszahlungen.
-**Kostenbasis:** FIFO (US-Norm), Specific-ID als Option.
**Noch offen / vom CPA zu bestätigen:**
1.**PDF-Library: PDFsharp/MigraDoc (MIT)** — nach Rückfrage bewusst statt QuestPDF: QuestPDFs
„Community MIT"-Lizenz ist nur unter 1 Mio USD Jahresumsatz kostenlos (darüber Professional/
Enterprise kostenpflichtig) → für eine handelnde LLC ein Lizenzrisiko. PDFsharp/MigraDoc ist echte
MIT ohne Schwelle.
2. **Steuerliche Einordnung (Default-Annahme):** Property-Disposition (Form 8949/Schedule D, Default) vs.
ordinary income vs. gambling vs. §1256 — vom US-CPA bestätigen lassen; im Tool umstellbar.
3. **LLC-Typ:** single-member (disregarded) vs. multi-member (Partnership 1065/K-1) — bestimmt nur die
Ziel-Formulare/Darstellung, nicht die Gewinnermittlung.
4. **USDC=USD-Annahme & Wash-Sale-Schalter:** Defaults gesetzt (1:1; Wash-Sale n/a) — vom CPA bestätigen.
5.**Proxy-Wallets: geklärt.** Der Gnosis-Safe (= vorhandene `WalletAddress`) ist die Watch-Adresse;
zu bauen ist die **Transfer-Klassifikation** intern (Polymarket-Contracts) vs. extern (Deposit/Withdrawal)
über eine System-Contract-Whitelist (CTF-Adresse bereits im Code; Exchange/NegRisk/USDC ergänzen).
6. **FX-Quelle & USDC/USD:** EZB-Tageskurse für USD→EUR; USDC→USD als 1:1 (Default) oder realer Kurs?
+129
View File
@@ -0,0 +1,129 @@
# Konzept: Eigenes datengetriebenes Trading-Modul („DataDriven")
> Stand: 2026-07-11
> Status: KONZEPT (noch kein Umsetzungsplan). Ziel: ein Strategiemodul, das eigene
> Handelsentscheidungen aus externen Datenquellen ableitet — je Marktkategorie eine
> eigene Datenquelle + ein eigenes Fair-Value-Modell. Die Datenanbindung wird so
> gebaut, dass das ResolutionFarming sie mitnutzen kann (State-aware-Filter, C-S2).
---
## 1. Grundidee
Alle bisherigen Module leiten Signale von ANDEREN ab (Master-Trades, Marktpreise).
DataDriven dreht das um: **Wir berechnen aus Rohdaten eine eigene faire
Wahrscheinlichkeit** und handeln nur, wenn der Marktpreis deutlich davon abweicht:
```
FairValue(Markt) aus Datenquelle → Vergleich mit Marktpreis (Bid/Ask)
→ |FairValue Preis| > MinEdge (nach Fees) → Order (Maker bevorzugt) → Halten bis Resolution/Ziel
```
Der Edge kommt nicht aus Geschwindigkeit, sondern daraus, die **Daten besser/
konsequenter auszuwerten als der Durchschnitts-Teilnehmer** der jeweiligen Kategorie.
Deshalb ist die Kategorien-Wahl die wichtigste Entscheidung dieses Moduls.
## 2. Architektur (fügt sich in die bestehende Modul-Landschaft)
```
PolyTrader.Modules.DataDriven (IPolyTraderModule, DbPrefix dd_)
├── Core-Beitrag (geteilt, auch für ResolutionFarming nutzbar):
│ IMarketStateProvider // je Kategorie: liefert konservative
│ { // Wahrscheinlichkeits-Schätzung + Zustand
│ bool Supports(MarketData m);
│ Task<MarketStateEstimate?> EstimateAsync(MarketData m, CancellationToken ct);
│ }
│ record MarketStateEstimate(decimal ProbLowerBound, decimal ProbUpperBound,
│ string StateSummary, DateTime AsOf, string Source);
├── Provider (je Kategorie ein Adapter, einzeln aktivierbar):
│ WeatherStateProvider // Open-Meteo/NOAA-Modelläufe
│ SportsScoreStateProvider // Live-Scores (z. B. API-Football)
│ CryptoStrikeStateProvider // Binance-Spot + realisierte Volatilität
│ MacroStateProvider // Nowcasts/Konsensdaten (CPI, Zinsen)
├── Services:
│ DdScannerService // Märkte je aktiver Kategorie laden, FairValue
│ // berechnen, Kandidaten mit Edge persistieren
│ DdExecutionService // Sizing/Limits (Muster: FarmingRiskEngine/
│ // Planner wiederverwenden!), Maker-first
│ DdPositionMonitorService // Re-Evaluation offener Positionen: dreht der
│ // FairValue, wird der Exit geprüft (Leiter-Muster)
└── Persistenz: dd_settings / dd_candidates / dd_positions / dd_closed_trades
(Kopie des bewährten rf_-Schemas; Autoincrement-IDs, Kalibrierungs-Historie)
```
**Wichtige Wiederverwendung:** Risk-Engine, Execution-Planner, Fill-Modell,
Resolution-Monitor und UI-Aufbau des ResolutionFarming sind fast 1:1 übertragbar —
DataDriven ist strukturell „ResolutionFarming mit eigener Signalquelle statt
Preisband-Scan". Der Unterschied: DataDriven darf auch UNTER 0.90 kaufen (überall,
wo FairValue ≫ Preis) und optional vor der Resolution verkaufen, wenn der Edge
realisiert ist (Preis hat FairValue erreicht → Kapitalumschlag).
**ResolutionFarming-Synergie (C-S2):** Sobald ein `IMarketStateProvider` für eine
Kategorie existiert, nutzt ihn auch der RF-Scanner: Ein Preis-Dip wird nicht mehr
pauschal gemieden (Momentum-Filter), sondern gegen `ProbLowerBound` geprüft —
Richards 5:1-in-Minute-80-Beispiel wird damit zur Kaufgelegenheit statt zum Reject.
## 3. Kategorien-Bewertung: Wo lohnt sich ein eigenes Modell?
Bewertung nach: Datenlage (frei/billig verfügbar?), Modell-Komplexität,
Bot-Konkurrenz (Stand 2026), Fee-Satz, Kapitalbindung.
| Kategorie | Datenquelle (Kosten) | Modell | Bot-Konkurrenz | Fee | Bindung | Urteil |
|---|---|---|---|---|---|---|
| **Wetter (Tages-Märkte: Temperatur/Niederschlag je Stadt)** | Open-Meteo/NOAA/ECMWF-Läufe (kostenlos) | Modell-Konsens vs. Marktpreis; Update-Lag nutzen | **moderat, wachsend** — Edges von ~10 Pp (2023) auf ~3 Pp (2026) komprimiert, aber vorhanden; dünne Bücher, wenig Retail | 1,25 % | StundenTage | ✅ **Bester Einstieg** |
| **Wetter (Saison: Hurrikane, Rekorde)** | wie oben + NHC | aufwendiger | gering (Kapital-Lockup schreckt ab) | 1,25 % | WochenMonate | ⚠️ später (Bindung) |
| **Sport pre-game (kleinere Ligen)** | API-Football o. ä. (~2030 $/Mon.) | Elo-/Quotenvergleich vs. Buchmacher-Konsens | groß in Top-Ligen, **moderat in Nebenligen** | 0,75 % | StundenTage | ✅ zweiter Kandidat |
| **Sport live (State-Provider)** | wie oben, Live-Scores | Score+Restzeit → P(Sieg), konservative Untergrenze | hoch (Latenz-Bots) — aber wir brauchen nur EINEN Fill unter FairValue, nicht den schnellsten | 0,75 % | MinutenStunden | ✅ als RF-Filter; als eigene Strategie nur eng begrenzt |
| **Krypto-Strikes (Wochen/Monat: „BTC über X am Y")** | Binance-WSS (kostenlos) | Distanz zum Strike + realisierte Vol → P | hoch bei 15-min/Stunde, **moderat bei Wochen-Strikes** | 1,8 % ⚠️ | TageWochen | ⚠️ Fee frisst viel; nur bei großem Modell-Edge |
| **Makro (CPI, Zinsentscheide)** | Cleveland-Fed-Nowcast, Konsens-Schätzungen (frei) | Nowcast vs. Marktpreis | moderat, aber informierte Gegenseite | 1,5 % | TageWochen | ⚠️ Nische, wenige Märkte |
| **Politik-Longtail (Nicht-Headline)** | Polls/Aggregatoren | Poll-Modell | gering im Long Tail | 1,0 % | Wochen+ | ⚠️ Bindung + Resolution-Risiko |
| **Kultur/Awards/Mentions** | Box-Office-Daten teils frei; sonst dünn | schwach | **gering** | 1,251,56 % | variabel | ❌ Resolution-Risiko (AI-Rater Pflicht), Datenlage schlecht |
| Krypto 15-min/1h Up-Down | Binance | Latenz | **extrem** (Sub-100-ms-Bots) | 1,8 % | Minuten | ❌ nicht unser Spiel |
**Antwort auf „nicht geflutete Kategorien":** Am wenigsten Bot-dominiert sind 2026
(a) **Wetter** — dünne Bücher, Nischenwissen (Stations-Regeln, Modell-Läufe), Retail
meidet die Kategorie; (b) **Long-Tail-/Nebenliga-Sport pre-game**; (c) **Makro-
Nischen** und (d) Long-Tail-Politik. Geflutet sind: Krypto-Kurzfrist, Top-Sport
in-play, Headline-Elections, Arbitrage/NegRisk-Rebalancing. Faustregel: Bots meiden
Kapitalbindung und Nischenwissen — genau dort liegt unser Fenster.
## 4. Empfohlener Aufbau-Pfad
1. **Phase DD-0:** `IMarketStateProvider`-Contract in Core + Modul-Skelett
(rf_-Schema kopieren). Kein Provider aktiv.
2. **Phase DD-1 (Wetter, read-only):** WeatherStateProvider (Open-Meteo, tägliche
Temperatur-Märkte 23 US-Städte). Scanner läuft wochenlang read-only:
FairValue vs. Marktpreis loggen → **misst den real verbliebenen Edge, bevor
irgendetwas gehandelt wird** (dasselbe Kalibrierungs-Gate-Prinzip wie RF).
3. **Phase DD-2:** Demo-Execution (Planner/Fill-Modell aus RF), 4 Wochen.
4. **Phase DD-3:** SportsScoreStateProvider — zuerst NUR als RF-Filter (C-S2:
Dip-Freigabe bei klarer Führung), erst danach als eigene DD-Strategie.
5. **Phase DD-4:** Live klein (eigener Account, wie bei RF), dann weitere Provider
nach gemessenem Edge.
## 5. Risiken dieses Moduls (ehrlich)
1. **Modell-Risiko ersetzt Master-Risiko:** Ein Bug/Bias im Fair-Value-Modell
produziert systematisch falsche Trades. Gegenmittel: read-only-Messphase je
Provider (DD-1-Prinzip), konservative Untergrenzen statt Punktschätzern.
2. **Edge-Kompression:** Der Wetter-Edge ist dokumentiert am Schrumpfen (10→3 Pp).
Read-only-Messung VOR jedem Livegang, und die Bereitschaft, eine Kategorie
wieder abzuschalten, wenn die Messung < MinEdge zeigt.
3. **Regel-Fallen:** Wetter-Märkte lösen nach exakten Stations-Regeln auf — der
AI-Auflösequalitäts-Rater (separater Plan) und das genaue Lesen der Regeln
je Markt-Serie sind Pflicht (welche Station, welche Rundung, welcher Zeitraum).
4. **Aufwand:** Jede Kategorie ist ein eigenes kleines Forschungsprojekt. Deshalb:
strikt eine Kategorie nach der anderen, jede mit eigenem Go/No-Go-Gate.
## 6. Quellen (Kategorien-/Konkurrenz-Einschätzung)
- Polymarket Weather/Climate-Kategorieübersichten (Volumen/Marktzahl):
https://polymarket.com/predictions/weather, https://polymarket.com/predictions/climate
- Weather-Bot-Funktionsweise & Edge-Kompression 2023→2026:
https://laikalabs.ai/prediction-markets/polymarket-weather-trading-bot
- Markt-Mikrostruktur/Tiefe Wetter-Märkte: https://polymart.app/blog/polymarket-weather-markets,
https://polymarkets.co.il/en/guide/weather-guide/
@@ -0,0 +1,127 @@
# Predictalytics: Prüf- und Ergänzungsplan für die Master-Trader-Auswahl
> Stand: 2026-07-11
> Zweck: Dieses Dokument geht an den Predictalytics-Agenten. Es beschreibt, welche
> Auswahl-Kriterien und Validierungsschritte die Master-Trader-Selektion für das
> PolyTrader-Copytrading erfüllen soll — zum Abgleich mit den bereits vorhandenen
> Berechnungen und als Ergänzungsliste. Predictalytics ist ein eigenständiges Projekt;
> dieses Dokument setzt KEINE Kenntnis des PolyTrader-Codes voraus.
---
## 1. Kontext: Wofür die Auswahl gebraucht wird
PolyTrader kopiert Trades ausgewählter Polymarket-Wallets („Master") auf eigene
Accounts. Zielprofil laut Strategie-Entscheidung: **Buy-and-Hold-Master** — Trader,
die Positionen kaufen und in der Regel bis zur Marktauflösung halten, mit
überdurchschnittlichem Erfolg. Bei diesem Typ ist die Kopier-Latenz fast irrelevant;
die Auswahlqualität entscheidet über ~90 % des Ergebnisses.
Wichtig für alle Metriken: Der Kopierende zahlt gegenüber dem Master einen
**Kopier-Aufschlag** (Spread + bis zu 2 % Limit-Aufschlag + 0,751,8 % Taker-Fee je
nach Kategorie; bei Maker-Einstieg weniger, dafür Fill-Risiko). Ein Master ist erst
dann kopierenswert, wenn sein Edge diesen Aufschlag DEUTLICH übersteigt.
## 2. Kern-Metriken je Wallet (prüfen ob vorhanden, sonst ergänzen)
Alle Metriken über ein definiertes Fenster (Vorschlag: 90 Tage) und nur über
**aufgelöste/geschlossene** Trades:
| # | Metrik | Definition | Warum |
|---|---|---|---|
| M1 | Edge pro Trade | Ø realisierter PnL in % des Einsatzes je Trade | Muss > Kopier-Aufschlag (~34 Pp) liegen; „profitabel" allein reicht nicht |
| M2 | Profit-Faktor | Bruttogewinn / Bruttoverlust | Robuster als Winrate (Favoriten-Käufer haben 95 % Winrate und können negativ sein) |
| M3 | Holder-Quote | Anteil Positionen, die per Resolution enden (nie aktiv verkauft) | Zielprofil-Filter: Zielwert nahe 100 % |
| M4 | Stop-Loss-Verhalten | Anteil SELLs, die NACH einem Preisrückgang ≥ X % erfolgen | Trennt „Stur-Halter" von „Stop-Loss-Nutzern" — Letztere sind fürs Kopieren ungeeignet (Exit-Latenz-Nachteil) |
| M5 | Trade-Frequenz & Stichprobe | Trades/Woche; Gesamtzahl im Fenster | Mindeststichprobe für alles Weitere (siehe 3.1) |
| M6 | Ø-Haltedauer | Median Stunden Kauf→Auflösung | Kapitalbindung des Kopierenden; plus Konsistenz-Indikator |
| M7 | Preisband-Profil | Verteilung der Einstiegspreise (z. B. je 10-¢-Band) | Charakterisiert die Strategie (Favoriten-Halter vs. Longshot-Spieler) |
| M8 | Kategorien-Mix | Einsatz-Anteil je Marktkategorie | Für Korrelations-/Portfolio-Betrachtung (siehe 5) und Fee-Rechnung |
| M9 | Einsatz-Disziplin | Verteilung der Positionsgrößen relativ zur Wallet | Erkennt Martingale-/Tilt-Muster (stark wachsende Einsätze nach Verlusten = rotes Tuch) |
## 3. Validierungs-Methodik (die drei klassischen Fallen)
### 3.1 Survivorship-/Glücks-Bias
Unter zehntausenden Wallets sehen einige rein zufällig brillant aus. Gegenmaßnahmen:
1. **Mindeststichprobe:** keine Bewertung unter ~100 aufgelösten Trades im Fenster.
2. **Out-of-Sample-Pflicht:** Auswahl auf Zeitfenster A (z. B. Tag 180 bis 60),
Bestätigung auf Fenster B (Tag 60 bis heute). Nur Master, die in BEIDEN Fenstern
die Schwellen erfüllen, kommen auf die Kopier-Liste. Master, die nur in A glänzen,
werden verworfen — egal wie gut A aussieht.
3. **Plausibilitäts-Check des Edges:** Bei Favoriten-Haltern lässt sich der Edge als
„realisierte Winrate je Einstiegs-Preisband vs. Preisband" ausdrücken (kauft er
95-¢-Shares, die zu 98 % gewinnen → +3 Pp Edge). Diese Darstellung bitte je Master
ausgeben — sie macht Glück von System unterscheidbar und ist direkt mit der
ResolutionFarming-Kalibrierung in PolyTrader vergleichbar.
### 3.2 Kopierbarkeit
Ein profitabler Master kann unkopierbar sein. Je Master prüfen:
1. **Markt-Liquidität:** Median-Liquidität/Volumen der gehandelten Märkte. Handelt er
in Kleinstmärkten, bewegt schon der Kopier-Kauf den Preis. Vorschlag: Median-Buch-
Tiefe oder 24h-Volumen der gehandelten Märkte als Kriterium, Schwelle empirisch.
2. **Edge-Verbleib nach Kopier-Aufschlag:** M1 minus 34 Pp muss > 0 bleiben
(Kategorie-Fee einrechnen: Sports 0,75 %, Politik 1,0 %, Krypto 1,8 %).
3. **Einstiegs-Fenster:** Wie schnell bewegt sich der Preis nach dem Master-Kauf?
(Median-Preisänderung 1 min / 10 min / 1 h nach seinen Fills, aus der Preis-
Historie). Läuft der Preis sofort weg, ist der Edge zeitkritisch → schlecht
kopierbar; bleibt er stabil, passt auch ein ruhender Maker-Einstieg.
### 3.3 Korrelation / Portfolio-Ebene
Nicht nur Einzel-Scores ranken — die Kopier-Liste ist ein Portfolio:
1. **Master-Korrelation:** Überlappung der gehandelten Märkte/Kategorien zwischen
Kandidaten (z. B. Jaccard auf ConditionIds, Kategorie-Mix-Ähnlichkeit). Drei gute
Wetter-Bots sind EIN Klumpenrisiko, nicht drei Ertragsquellen.
2. **Empfehlung als Portfolio:** Ausgabe nicht nur als Rangliste, sondern als
diversifizierter Vorschlag (z. B. max. 2 Master je Kategorie-Schwerpunkt).
## 4. Verhaltens-Fingerprint als Basisdaten (Übergabe an PolyTrader)
PolyTrader soll Strategie-Drift der Master zur Laufzeit erkennen (separater Plan
dort). Dafür braucht es je ausgewähltem Master eine **Baseline**, die Predictalytics
ohnehin berechnet — bitte mit exportieren: Trade-Frequenz/Woche, Kategorien-Mix,
Einstiegs-Preisband-Verteilung, Median-Haltedauer, Positionsgrößen-Verteilung
(jeweils Fenster B). Format: JSON je Wallet.
## 5. Übergabe-Format an PolyTrader (Vorschlag)
Je empfohlenem Master ein Datensatz:
```json
{
"wallet": "0x…",
"displayName": "…",
"classification": "HOLDER", // HOLDER | STOPLOSS | MIXED — nur HOLDER wird kopiert
"windowA": { "trades": 214, "edgePerTradePct": 6.1, "profitFactor": 2.4, "holderRatio": 0.98 },
"windowB": { "trades": 180, "edgePerTradePct": 5.4, "profitFactor": 2.1, "holderRatio": 0.99 },
"copyability": { "medianMarketVolumeUsd": 120000, "postFillDrift10minPct": 0.4, "netEdgeAfterCopyCostsPct": 2.1 },
"categoryMix": { "Sports": 0.7, "Politics": 0.3 },
"fingerprintBaseline": { "tradesPerWeek": 38, "medianHoldHours": 22, "priceBands": { "0.90-0.95": 0.6, "0.95-0.99": 0.3 }, "sizeP90Usd": 450 },
"riskFlags": ["…"] // z. B. Martingale-Verdacht, Kategorie-Klumpen
}
```
## 6. Akzeptanzkriterien des Prüflaufs
1. Jede Kern-Metrik (M1M9) ist je Kandidat berechnet oder als „nicht berechenbar"
mit Grund markiert.
2. Kein Master auf der Empfehlungsliste ohne bestandene Out-of-Sample-Bestätigung
und Mindeststichprobe.
3. Klassifikation HOLDER/STOPLOSS/MIXED je Kandidat mit den zugrunde liegenden
Zahlen (M3/M4) nachvollziehbar.
4. Die Empfehlungsliste enthält die Korrelations-/Portfolio-Betrachtung (5.).
5. Export im Übergabe-Format (5.) für den PolyTrader-Import.
## 7. Offene Fragen an Predictalytics (bitte im Ergebnis beantworten)
1. Welche der Metriken/Validierungen existieren bereits, welche wurden ergänzt?
2. Wie viele Wallets überleben die volle Filterkette (Funnel-Zahlen je Stufe)?
Wenn < 3: Welche Schwelle ist der Engpass, und wie sähe eine begründete
Lockerung aus (statt stillschweigend zu lockern)?
3. Wie aktuell sind die Daten (Lag der Datenquelle), und wie oft kann die
Auswahl neu gerechnet werden (Ziel: mindestens wöchentlich)?
@@ -0,0 +1,122 @@
# US Tax Treatment Questionnaire — Polymarket Trading Operations (Florida LLC)
*Prepared for our US CPA / tax advisor. Purpose: determine the correct federal tax treatment and the
exact report formats so our in-house accounting tool computes and exports precisely what you need.*
---
## Context
We operate automated trading strategies on **Polymarket** — a blockchain-based prediction-market /
event-contract platform — through a **Florida LLC**. Positions settle in **USDC** (a USD-pegged
stablecoin) on the Polygon network via Polymarket's smart contracts and **Gnosis-Safe proxy wallets**.
We are building an in-house accounting tool that:
- Independently pulls **every transaction of every trading account directly from Polymarket** (not from
our own trading database) and stores an **immutable, audit-traceable ledger** — each entry backed by a
blockchain transaction hash / platform activity ID and a stored raw-data snapshot.
- Reconciles each account against its **on-chain USDC balance** as a completeness check.
- Produces **per-account and consolidated period statements** (monthly and custom date ranges) and will
produce **US federal tax computations** (Form 8949 / Schedule D-style) under assumptions **you specify**.
**Transaction/event types we capture per account:** buys, sells, redemptions (winning-position payouts at
market resolution), losing positions expiring worthless, trading fees, maker rewards / rebates, on-chain
USDC deposits and withdrawals.
Where a treatment is uncertain, we will implement **your chosen approach as a documented, configurable
assumption** that is disclosed on every export. Please answer as many items as are relevant.
---
## A. Entity, filing & registration
1. Federal classification of the LLC: **single-member (disregarded entity)** or **multi-member
(partnership, Form 1065 + Schedules K-1)**? Any election to be taxed as **S-corp / C-corp**
(Form 2553 / 8832)?
2. Which federal forms/schedules will this activity flow into (e.g., Schedule C, Schedule D + Form 8949,
Form 1065/K-1, Form 4797)?
3. Florida has no personal state income tax — is there anything at the entity level we must reflect, or
is this **federal only**? Any Florida annual-report items affecting our accounting?
4. EIN and tax year (we assume calendar year)?
## B. Character & classification of Polymarket P&L
5. How should gains/losses from Polymarket **event contracts** be characterized: **capital gains/losses**
(Form 8949 / Schedule D), **ordinary income**, **gambling winnings/losses**, **§1256 contracts**
(60/40, mark-to-market), or **other**?
6. Do you regard these instruments as **securities, commodities, swaps, wagering transactions, or
property**? Does the characterization differ by market type (e.g., sports vs. politics vs. crypto-price)?
7. If capital: our holding periods are effectively always **under one year** — do you want everything
reported as **short-term**, or should we still compute per-lot holding periods (acquisition → disposition)?
8. If gambling treatment applies: how should we present winnings vs. losses (losses limited to winnings;
per-wager vs. session netting)?
## C. Trader Tax Status & §475(f) mark-to-market
9. Given the volume and automation, could the LLC qualify for **Trader Tax Status (TTS)**? Do you
recommend a **§475(f) mark-to-market election** (ordinary gain/loss, no wash-sale, no capital-loss
limitation, year-end MTM)?
10. If §475(f) MTM applies, what **price source and timing** would you accept to mark **open positions**
at period/year end (last trade, mid-price, resolution probability)?
11. **Self-employment tax:** does this activity create SE-tax exposure, or is it exempt (trading gains
generally not SE income)?
## D. Cost basis & lot accounting
12. Cost-basis method: **FIFO** (our default), **specific identification**, or other? Any documentation
requirements for specific-ID?
13. Should trading **fees** be **capitalized into basis / netted against proceeds**, or deducted
**separately** as expenses?
14. **Redemption** (winning shares pay out at resolution): treat as a disposition at **$1.00/share**
proceeds against lot basis? **Losing shares** expiring worthless: treat as a disposition at **$0**
(realized loss) on the resolution date?
15. Partial fills within one transaction: acceptable to **aggregate same-tx fills into one lot**?
## E. USDC / stablecoin treatment
16. May we treat **USDC as a USD cash-equivalent (1:1)**, so acquiring/spending USDC is **not** itself a
separate taxable crypto disposition? Or must USDC be tracked as **property** with its own basis?
17. If USDC must be tracked as property, what **USD valuation source/timing** per transaction do you require?
## F. Wash-sale & related rules
18. Do **wash-sale rules (§1091)** apply to these instruments (they are not traditional "stock or
securities," and crypto is currently generally exempt)? If potentially applicable, should the tool
**flag/adjust** wash sales?
19. Are **straddle (§1092)** or **constructive-sale** rules relevant to any hedged/paired positions?
## G. Income items & deductions
20. **Maker rewards / liquidity rebates** received in USDC: **ordinary income at fair value on receipt**?
Where reported? Does receipt create a **new USDC lot** at that value?
21. Deductible business **expenses** (platform/trading fees, Polygon gas/POL, infrastructure, software,
this tooling): where and how (Schedule C vs. netted)?
22. Will Polymarket issue any **1099** (likely not, as a non-US operator)? If so, how should we reconcile to it?
## H. Foreign account / information reporting
23. Is a Polymarket account (funds in a Polygon **Gnosis-Safe proxy** on a non-US platform) a **"foreign
financial account"** triggering **FBAR (FinCEN Form 114)** above the $10,000 aggregate threshold?
24. Does **FATCA / Form 8938** reporting apply (specified foreign financial assets)?
25. Is **Form 8886** (reportable transactions) or any other information return relevant?
26. Any concerns arising from Polymarket's **US regulatory status** that affect characterization or reporting?
## I. Currency & valuation
27. Reporting/functional currency: **USD** confirmed? We also generate **EUR** figures — needed for the US
filing, or purely internal/EU personal use?
28. FX source/timing: for non-USD figures, is the **ECB daily reference rate at transaction date**
acceptable? For **USDC→USD**, is **1:1** acceptable or do you require actual spot?
## J. Report format & delivery (so we tailor exports to you)
29. Preferred deliverables: **Form 8949 CSV in the exact IRS column layout**, a **general-ledger** export,
a **Schedule D summary**, and/or a **PDF statement**? Which formats do you want?
30. Level: **per-account** statements, a **consolidated LLC** view, or both?
31. Cadence: **monthly** bookkeeping packages plus an **annual** tax package? Do you need **quarterly
estimated-tax** figures?
32. Exact **columns/fields** on the disposition report (e.g., Description of property, Date acquired, Date
sold, Proceeds, Cost basis, Wash-sale adjustment, Gain/loss, Short/Long)?
33. **Audit-defensibility** documentation you want attached (methodology page, source transaction hashes,
raw-data retention, reconciliation to on-chain balances)?
34. Rounding/precision conventions (whole USD vs. cents)?
## K. Anything else
35. Any other **elections, forms, thresholds, or record-keeping standards** we should build into the tool
now to make your work smooth and the LLC's filings defensible?
---
*We will encode your answers as the tool's default assumptions, each disclosed on every statement and
adjustable in settings. Thank you.*
@@ -0,0 +1,126 @@
# Umsetzungsplan: AI-Bewertung der Auflösequalität (C-S4)
> Stand: 2026-07-11
> Ziel: Ein LLM (via OpenRouter) bewertet je Markt das RESOLUTION-Risiko (subjektive
> Auflösequellen, Regeltext-Fallen, UMA-Dispute-Muster). Die Bewertung wird beim
> Markt-Import in der DB gespeichert und dient als Entry-Gate — zuerst im
> ResolutionFarming, perspektivisch auch im Copytrading.
> Einordnung: Core-Baustein (beide Module profitieren), kein eigenes Strategiemodul.
---
## 1. Abgrenzung (wichtig für die Umsetzung)
Das LLM prognostiziert NICHT den Markt-Ausgang. Es beantwortet ausschließlich:
**„Wie sauber/objektiv wird dieser Markt aufgelöst werden?"** — Input ist der
Regeltext, nicht das Weltgeschehen. Das hält die Aufgabe eng, billig und testbar.
## 2. Architektur
### 2.1 Core-Service `IMarketRiskRater` (PolyTrader.Core)
```csharp
public interface IMarketRiskRater
{
/// Liefert die (ggf. gecachte) Bewertung; null wenn (noch) keine vorliegt.
Task<MarketRiskRating?> GetOrRateAsync(MarketData market, CancellationToken ct);
}
public class MarketRiskRating // Tabelle core_market_risk_ratings
{
public string ConditionId { get; set; } // PK — Regeltexte ändern sich nicht → dauerhaft cachebar
public int Score { get; set; } // 0100 (100 = völlig objektiv auflösbar)
public string Flags { get; set; } // CSV: SUBJECTIVE_SOURCE, DEADLINE_AMBIGUITY,
// MENTIONS_TYPE, DISPUTE_PATTERN, MISSING_RULES
public string Reason { get; set; } // Einzeiler-Begründung des Modells
public string Model { get; set; } // verwendetes Modell (Nachvollziehbarkeit)
public DateTime RatedAt { get; set; }
}
```
### 2.2 `OpenRouterClient` (Core, dünn)
- HTTP-Client gegen https://openrouter.ai/api/v1/chat/completions, API-Key aus
appsettings (`OpenRouter:ApiKey`, gitignoriert wie andere Secrets).
- **Modellwahl:** günstiges Modell reicht (Haiku-Klasse, z. B.
`anthropic/claude-haiku-4.5` via OpenRouter; Modell-ID als Setting, nicht
hartkodieren). Kosten je Markt: Bruchteile eines Cents; mit Cache je ConditionId
einmalig pro Markt.
- **Structured Output:** Antwort als JSON erzwingen (Schema im Prompt + JSON-Mode);
bei Parse-Fehler 1 Retry, danach „kein Rating" (fail-closed, siehe 3.3).
- Timeout kurz (~15 s), Fehler loggen, NIE den aufrufenden Scanner blockieren.
### 2.3 Prompt (Kern, bei Umsetzung feinjustieren)
Input je Markt: `Question`, `Description`/Resolution-Kriterien (Gamma-API liefert
den Regeltext am Markt-Objekt — Feld bei Umsetzung verifizieren), Kategorie, EndDate.
Bewertungsauftrag an das Modell (sinngemäß):
1. Gibt es eine EINDEUTIGE, öffentlich prüfbare Auflösequelle (offizielles
Endergebnis, behördliche Zahl, On-Chain-Fakt)?
2. Sind Randfälle geregelt (Verschiebung, Abbruch, Unentschieden, Definitionsfragen
wie „offiziell angekündigt")?
3. Ähnelt der Markt bekannten Streit-Mustern (Mentions-/„sagt X"-Märkte, vage
Deadlines, Definitions-Ambiguität, mehrdeutige Quellen)?
Output: `{ "score": 0-100, "flags": [...], "reason": "…" }`.
## 3. Integration
### 3.1 Wann wird bewertet?
Beim Markt-Import bzw. beim ersten Kontakt: Der **RF-Scanner** ruft
`GetOrRateAsync` für jeden Kandidaten auf, der alle billigen Filter passiert hat
(NACH Preisband/Kategorie/Fenster, VOR dem Accept — kein LLM-Call für offensichtliche
Rejects). Cache macht Wiederholungs-Scans kostenlos.
### 3.2 Entry-Gate im ResolutionFarming
Neue `RfSettings`:
- `MinResolutionScore` (Default 70): Kandidaten mit Score darunter → Reject mit
Grund `"AI-Resolution-Score {score} < {min}: {reason}"` (landet wie alle Rejects
in rf_candidates → die Kalibrierung kann später prüfen, ob das Gate Geld spart!).
- `RequireRating` (Default true): fail-closed-Schalter (siehe 3.3).
### 3.3 Fail-Closed-Regeln (Sicherheitskern)
1. Kein Rating verfügbar (API down, Parse-Fehler, kein Regeltext) → Kandidat gilt
als riskant und wird abgelehnt — AUSSER die Kategorie steht auf einer
Objektiv-Whitelist (Default: Sports-Endergebnisse), dann Durchlass mit Log.
2. Das Rating **ersetzt die harte Blacklist nicht**: bekannte Giftmuster
(Mentions-Märkte etc.) bleiben in `BlacklistCsv` hart geblockt. Das LLM ist die
zweite Verteidigungslinie für den Long Tail, nicht die erste.
3. **Post-Mortem-Pflicht:** Jeder real erlebte Dispute → Muster in Blacklist/Prompt
aufnehmen. Dafür Flag-Feld in rf_closed_trades (`ResolutionDisputed`) vorsehen.
### 3.4 Copytrading (zweiter Schritt, optional)
Gleicher Service: Vor einem BUY den Score prüfen; unter Schwelle → Trade
verwerfen mit TradeReasoning-Log. Als Per-Account-Setting (`MinResolutionScore`,
0 = aus), Default zunächst AUS, um das Copy-Verhalten nicht zu verändern, bis der
Rater validiert ist.
## 4. Validierung VOR dem Scharfschalten (Pflicht-Phase)
1. **Retrospektiv-Test:** ~1520 öffentlich bekannte, umstrittene UMA-Resolutions
(Recherche-Aufgabe: bekannte Dispute-Fälle) + ~30 unstrittig aufgelöste
Vergleichsmärkte durch den Rater schicken. Messen: erwischt er die Streitfälle
(niedriger Score), ohne die sauberen zu blockieren?
2. **Akzeptanz:** ≥ 80 % der Streitfälle unter der Schwelle, ≤ 10 % der sauberen
fälschlich blockiert. Sonst Prompt/Schwelle iterieren.
3. Ergebnisse als Testdaten einfrieren (Golden-File-Test, läuft ohne API gegen
gespeicherte Antworten — kein LLM-Call in der CI).
## 5. Phasen
| Phase | Inhalt | Akzeptanz |
|---|---|---|
| AR-1 | OpenRouterClient + IMarketRiskRater + Tabelle/Migration + Unit-Tests (Parsing, Fail-Closed) | Build grün; Rater liefert für einen Beispiel-Regeltext strukturiertes Rating |
| AR-2 | Retrospektiv-Validierung (4.) | Akzeptanzquoten erreicht, dokumentiert |
| AR-3 | RF-Integration (3.1/3.2/3.3) + UI-Spalte (Score in Kandidaten-Tab) | Rejects mit AI-Grund sichtbar; Kalibrierung kann Gate-Wirkung auswerten |
| AR-4 | Copytrading-Integration (3.4), Default aus | Setting vorhanden, dokumentiert |
## 6. Leitplanken
- API-Key nie committen; Kosten-Deckel (max. Ratings/Tag als Setting, Default 500).
- Der Rater beeinflusst NIE Exits, nur Entries (keine Panik-Verkäufe durch LLM).
- Score/Reason immer mitloggen — Entscheidungen müssen im Log nachvollziehbar sein.
@@ -0,0 +1,117 @@
# Umsetzungsplan: On-Chain-Auto-Redeem (modulweise schaltbar)
> Stand: 2026-07-11
> Ziel: Gewonnene Positionen automatisch on-chain einlösen (Shares → USDC), als
> **Core-Baustein** mit **Aktivierung je Modul**. Richards Anforderung: In Testphasen
> neuer Module soll Auto-Redeem gezielt AUS bleiben können, um die Performance der
> Entwicklung manuell nachvollziehen zu können — ohne dass andere, etablierte Module
> ihren Automatismus verlieren.
> ⚠️ Höchste clob.md-Kritikalität: On-Chain-Signing mit echten Private Keys.
> Jede Phase: Backup/Commit vorher, Testmarkt/Kleinstbetrag zuerst.
---
## 1. Architektur: Queue statt Direktaufruf
Module redeemen nie selbst. Sie melden einlösbare Positionen in eine zentrale
Queue; ein Core-Worker arbeitet sie ab — nur für Module, deren Auto-Redeem aktiv ist.
```
Modul (RF-Monitor, CT-Sync, später DD) PolyTrader.Core
│ erkennt „Position gewonnen & aufgelöst" │
├── IRedeemQueue.Enqueue(RedeemRequest) ─────────────▶│ Tabelle core_redeem_queue
│ (immer! unabhängig vom Schalter) │
│ ▼
│ OnChainRedeemWorker (BackgroundService)
│ • nur Requests von Modulen mit AutoRedeemEnabled
│ • Rest bleibt als "Manual" sichtbar (UI-Liste)
▼ • CTF redeemPositions / NegRiskAdapter
UI je Modul: Pending-Redeems-Ansicht • Verifikation über USDC-Balance-Delta
```
**Warum immer enqueuen:** Auch bei deaktiviertem Auto-Redeem entsteht so eine
vollständige, je Modul gefilterte „zum Redeem bereit"-Liste (Dashboard/UI) — genau
die Übersicht, die Richard in Testphasen für die manuelle Betreuung will. Der
Schalter entscheidet nur, ob der Worker sie abarbeitet.
### 1.1 Datenmodell (`core_redeem_queue`)
| Feld | Inhalt |
|---|---|
| Id (auto) | PK |
| ModuleName | "ResolutionFarming" / "CopyTrading" / … |
| AccountId, TokenId, ConditionId | Ziel der Einlösung (ConditionId zwingend — für den Contract-Call) |
| IsNegRisk | Adapter-Wahl |
| SizeShares, ExpectedUsd | erwartete Auszahlung (Shares × 1.00) |
| Status | Pending / Processing / Done / Failed / Manual |
| Attempts, LastError, EnqueuedAt, CompletedAt, TxHash | Betrieb/Nachvollziehbarkeit |
### 1.2 Schalter
- **Je Modul:** `core_module_settings` (oder appsettings-Sektion) —
`AutoRedeem:ResolutionFarming = false`, `AutoRedeem:CopyTrading = false`
(Default IMMER aus; bewusstes Einschalten je Modul).
- **Global-Not-Aus:** `AutoRedeemGlobalEnabled` (analog GlobalTradingPaused,
Quickbar-Toggle) — schlägt alle Modul-Schalter.
- UI: Schalter je Modul in dessen Settings-Tab + Anzeige im Core-Dashboard,
welche Module aktiv sind.
## 2. Der On-Chain-Teil (`OnChainCtfService`, Core)
1. **Bibliothek:** Nethereum (bereits als Abhängigkeit im Projekt für EIP-712-Signing
vorhanden) — Contract-Calls über die bestehende Alchemy-RPC-Anbindung (Polygon).
2. **Aufrufe:** Standard-Markt: ConditionalTokens `redeemPositions(collateral,
parentCollectionId=0x0, conditionId, indexSets)`; NegRisk-Markt: über den
NegRisk-Adapter. **Contract-Adressen + ABI + indexSets-Ermittlung bei Umsetzung
zwingend aus https://docs.polymarket.com (Developer/CTF) verifizieren — nicht aus
dem Gedächtnis kodieren.** Die USDC-/CTF-Adressen als Konstanten mit Quellenangabe.
3. **Gas:** Wallet braucht POL. Vor jedem Call Balance-Check; unter Schwelle
(Setting, z. B. 0.5 POL) → Request auf `Manual` + Threema-Warnung „POL nachfüllen".
Gas-Preis: Standard-Estimation, Cap als Setting.
4. **Verifikation = Wahrheit:** Ein Redeem gilt erst als `Done`, wenn (a) die Tx
bestätigt ist UND (b) das USDC-Balance-Delta ≈ ExpectedUsd (Toleranz) gemessen
wurde. Sonst `Failed` mit Fehlertext.
5. **Retry:** max. 3 Versuche mit Backoff (1/10/60 min), danach `Manual` + Threema.
Idempotenz beachten: vor jedem Versuch prüfen, ob die Position on-chain überhaupt
noch einlösbar ist (bereits redeemte Shares → als Done werten, nicht als Fehler).
## 3. Modul-Integration
### 3.1 ResolutionFarming (erster Nutzer)
`FarmingResolutionMonitorService` setzt heute `RedeemStatus = "Pending"` am
RfClosedTrade. Ergänzung: beim Schließen eines Gewinners → `IRedeemQueue.Enqueue`.
Worker-Callback (oder Status-Poll) aktualisiert `RedeemStatus` (Pending → Redeemed/
Manual/Failed) → sichtbar im Historie-Tab. **Wichtig für Richards Testphasen-
Anforderung:** Der realisierte PnL ist bereits bei Resolution gebucht; der Redeem
ändert nur die Kapitalverfügbarkeit. Die Performance-Auswertung bleibt also mit und
ohne Auto-Redeem identisch — nur die Bankroll-Rotation unterscheidet sich.
### 3.2 CopyTrading (zweiter Nutzer)
Im `TraderMonitorService` existiert die Stelle bereits: der auskommentierte
Python-Redeem-Block im Resolution-Fallback („bereit für manuellen Redeem")
— dort `Enqueue` statt Kommentar. Gleicher PnL-Hinweis wie oben.
### 3.3 Künftige Module
Contract: Ein Modul, das Positionen bis Resolution hält, ruft bei „gewonnen &
aufgelöst" genau einmal `Enqueue` und liest optional den Status zurück. Mehr nicht.
## 4. Phasen & Akzeptanzkriterien
| Phase | Inhalt | Akzeptanz |
|---|---|---|
| RD-1 | Queue-Tabelle + IRedeemQueue + Modul-Schalter + UI-Pending-Liste (noch KEIN On-Chain-Code) | Module enqueuen; Liste zeigt je Modul „bereit zum Redeem"; Schalter sichtbar; 100 % ohne Live-API testbar |
| RD-2 | `OnChainCtfService` gegen Polygon: zuerst READ-only (Balance, Einlösbarkeits-Check) | Balance-/Zustandsabfragen stimmen gegen Polygonscan |
| RD-3 | Erster echter Redeem: EIN Testmarkt, Kleinstbetrag, manuell getriggert (Button an der Pending-Liste) | Tx bestätigt, USDC-Delta verifiziert, Status Done |
| RD-4 | Worker-Automatik scharf für RF (Schalter an), CT folgt nach Beobachtung | 1 Woche fehlerfreier Betrieb, Failed-Quote < 5 %, POL-Warnung getestet |
## 5. Leitplanken
1. `.agents/rules/clob.md` gilt verschärft: Private-Key-Nutzung außerhalb des
erprobten Order-Signing-Pfads. Jede Phase einzeln committen; RD-3 nie
überspringen.
2. Der Worker fasst NUR Queue-Einträge an — er scannt nie selbst Positionen
(klare Verantwortung: Module erkennen, Core löst ein).
3. Alle Beträge/TxHashes loggen; Threema-Tageszusammenfassung „X Redeems, Y USDC
freigesetzt, Z manuell offen".
4. Manuelle Redeems (über die Website) müssen erkannt werden: Einlösbarkeits-Check
in 2.5 markiert extern eingelöste Einträge als Done statt Failed.
@@ -0,0 +1,314 @@
# Umsetzungsplan: Copytrading-Modul — Rentabilitäts-Verbesserungen
> Stand: 2026-07-06
> Ziel: Bekannte Verlustquellen im Copytrading-Modul beseitigen und die
> Rentabilität durch datengetriebene Trader-Auswahl, echte Fill-Daten und
> besseres SELL-Handling steigern.
> Reihenfolge: **Dieser Plan zuerst.** Phase 1 (Marktdaten-Fundament) ist
> Voraussetzung für die Strategiemodule MarketMaking und BundleArbitrage.
---
## 0. Kontext & Hintergrund (für die Umsetzung ohne Vorwissen)
Das Copytrading-Modul (`src/PolyTrader.Modules.CopyTrading/`) kopiert Trades von
Master-Tradern auf Polymarket. Signalkette:
1. `AlchemyWebsocketService` erkennt On-Chain-Events der Master-Wallets (WSS).
2. `TraderMonitorService.TriggerFastBlockchainPoll()` parst die Transaktion direkt
(Fast Track, ~34 s hinter dem Master) oder fällt auf Data-API-Polling zurück.
3. Signale (`CopySignal`) laufen über einen Channel in die `CopyTradingEngine`.
4. Die Engine prüft Risiko-Limits (`CopyTradingAccountSettings`: PerMarketLimit,
PerMasterLimit, Zeitfenster-Limits, MaxBuyPrice) und platziert CLOB-Orders
über `PolymarketClobClient` (Core).
**Historischer Kontext (wichtig!):** Eine Verlustanalyse im April 2026
(`agentspace/prompts/AnalyzingOvernightTradingLosses.md`) hat als Hauptursache
für Overnight-Verluste identifiziert, dass der Bot SELLs der Master mit
Market-Orders ins leergeräumte Orderbuch kopiert und so zur „Exit-Liquidity"
wird (Beispiel: Entry 0.51, Master-Exit 0.99, unser Exit 0.49). Der damalige
Fix (GTD-Limit-Sells) ist **im aktuellen Modul-Code nicht mehr vorhanden**
vermutlich bei der Modularisierung verloren gegangen.
**Seit März 2026 erhebt Polymarket Taker-Fees** (Sports ~0,75 %, Politik/Finanzen
~1,0 %, Krypto ~1,8 %, am 50-¢-Preis am höchsten, Richtung 1 ¢/99 ¢ abnehmend;
Maker zahlen nichts und erhalten Rebates). Der Bot ist heute fast immer Taker.
Quelle: https://docs.polymarket.com/trading/fees — **bei Umsetzung aktuellen
Stand verifizieren.**
### Leitplanken (gelten für alle Phasen)
1. `.agents/rules/clob.md` beachten: Änderungen an der CLOB-Integration sind
hochkritisch. Vor jeder Änderung Backup/Commit der alten Version, jede
Änderung mehrfach prüfen.
2. Jede Phase lässt die App baubar und lauffähig zurück (Debug-Build grün).
3. Entscheidungslogik als testbare, pure Funktionen extrahieren und in
`PolyTrader.Tests` (xUnit, existiert bereits) abdecken.
4. Kein Livegang einer Phase ohne mehrtägige Beobachtung auf dem Server.
---
## Phase 0 — Sofortmaßnahmen: Blutung stoppen
### 0.1 🔴 SELL-Exit-Liquidity-Regression beheben (höchste Priorität)
**Befund:** In `CopyTradingEngine.cs` (Live-SELL-Pfad, aktuell ~Zeile 694735)
werden SELLs als `"MARKET"` mit Fallback-Limit `0.01m` gesendet:
```csharp
decimal sellLimit = 0.01m; // Market Order Fallback Limit
...
var result = await _clob.PlaceOrderAsync(account, signal.TokenId, signal.Side,
expectedUsdc, sellLimit, "MARKET", _state.DebugOrderPayloadLog, isNegRisk);
```
Das ist exakt das Verhalten, das die April-Verluste verursacht hat.
**Ziel-Design: Eskalationsleiter statt Market-Order**
1. Referenzpreis = `signal.Price` (Exit-Preis des Masters).
2. Erste Order: GTD-Limit.
- HF-Trader (`trader.Category == "HF"`): `signal.Price - 0.005m`.
- Sonst: `signal.Price * (1 - settings.MaxPriceDifference / 100m)`.
3. Neuer Setting-Wert `SellFloorPct` in `CopyTradingAccountSettings`
(Default z. B. 15 %): absolute Untergrenze = `signal.Price * (1 - SellFloorPct/100)`.
4. Hintergrund-Loop (Erweiterung von `CleanupStaleOpenOrdersAsync` in
`TraderMonitorService` oder eigener Loop): Order nach T Sekunden ohne Fill
(HF: ~20 s, sonst: ~120 s) canceln und eine Stufe tiefer neu platzieren
(Schrittweite z. B. 2 ¢ oder 3 % relativ), bis zum Floor.
5. Floor erreicht und kein Fill → Position halten, **Threema-Benachrichtigung**
senden (`ThreemaService` im Core existiert) und Position als „ExitPending"
markieren.
6. Position darf **nicht mehr optimistisch** aus `account.OpenPositions`
entfernt werden. Stattdessen Flag `ExitPending` (neues Property auf
`Position` oder Tracking-Dictionary im `CopyTradingState`), damit Limits
weiterhin korrekt rechnen und kein Doppel-SELL entsteht. Entfernen erst,
wenn der Fill über Sync/User-Channel (Phase 1) bestätigt ist.
**Preis-/Stufenlogik als pure statische Funktion** implementieren (z. B.
`SellLadder.NextPrice(referencePrice, step, floor, attempt)`) und mit
Unit-Tests abdecken.
**Akzeptanzkriterien:**
- Kein Code-Pfad sendet mehr `"MARKET"`-SELLs mit 0.01-Limit.
- Unit-Tests für Ladder-Preise (HF/normal, Floor-Clamping, 0.01/0.99-Grenzen).
- Log zeigt pro SELL: Referenzpreis, gewähltes Limit, Stufe.
### 0.2 Fee-Modell einführen
1. Fee-Rate je Markt beschaffen: Die CLOB-/Gamma-API liefert Fee-Informationen
am Markt-Objekt (Feldname bei Umsetzung anhand
https://docs.polymarket.com/trading/fees verifizieren, z. B. `fee_rate_bps`).
Fallback: statische Kategorie-Tabelle (Sports 0.75 %, Politics/Finance 1.0 %,
Crypto 1.8 %, Geopolitics 0 %).
2. `MarketData` (Core) um `TakerFeeBps` erweitern (EF-Migration Core),
Befüllung über `MarketSyncService` bzw. beim Markt-Fetch.
3. Risk-Check in `CopyTradingEngine`: erwartete Fee vom verfügbaren Edge
abziehen; Mikro-Trades, deren Fee den erwartbaren Gewinn frisst, verwerfen
(Logging mit Begründung wie bei den bestehenden Checks).
4. PnL-Berechnung (Demo **und** Live-Anzeige) um Fees korrigieren.
**Akzeptanz:** Fee erscheint im TradeReasoning-Log jedes BUY; Demo-PnL weist
Fees aus.
### 0.3 `ProfitTarget` implementieren oder entfernen
`CopyTradingAccountSettings.ProfitTarget` (Default 50.0) existiert in Settings,
DB und UI, wird aber **nirgends ausgewertet** (toter Knopf).
**Empfehlung: implementieren** als optionaler Take-Profit:
- Semantik: `0` = deaktiviert; sonst Prozent-Gewinnschwelle.
- Prüfung im 30-s-Live-Sync (`PollLiveAccountsAsync`): wenn
`CurrentPrice >= EntryPrice * (1 + ProfitTarget/100)` → Verkauf über die
Eskalationsleiter aus 0.1 (Startlimit = CurrentPrice), ExitReason
`"Profit Target"`.
- Zusammenspiel mit `PreRedeemLimit` beachten (beide können feuern —
PreRedeem hat Vorrang, da näher an 1.00).
### 0.4 Kleinere Konsistenz-Fixes
1. **20-Sekunden-Spam-Blockade** (`PendingOrderTimestamps`-Check am Anfang des
SELL-Pfads): blockiert aktuell auch legitime SELLs, wenn der Master < 20 s
nach dem Kauf aussteigt. Fix: Blockade nur für gleichgerichtete Orders
(BUY nach BUY), SELL nach BUY zulassen.
2. **`_state.GlobalPnl`**: wird in `PollLiveAccountsAsync`-Close-Pfaden addiert,
in `PollClosedAccountsAsync` nicht → Anzeige driftet. Vereinheitlichen.
3. **Demo-`ClosedTrade` ohne `TokenId`**: Im Demo-SELL-Pfad wird `TokenId` nicht
gesetzt (Preload von `_processedClosures` filtert auf `TokenId`). Setzen.
---
## Phase 1 — Marktdaten-Fundament (Core-Infrastruktur)
> Diese Phase gehört in **PolyTrader.Core** (`src/PolyTrader.Core/Streaming/`),
> nicht ins Modul — MarketMaking- und BundleArbitrage-Modul (separate Pläne)
> setzen sie voraus.
### 1.1 CLOB User-Channel (echte Fills in Echtzeit)
Polymarket bietet einen authentifizierten WSS-User-Channel, der Order-Events
(Platzierung, Teil-/Voll-Fill, Cancel) der eigenen Accounts pusht.
Endpoint/Protokoll bei Umsetzung verifizieren:
https://docs.polymarket.com (CLOB WSS, `user` channel; Auth via API-Key/
Secret/Passphrase — liegen je Account in `AccountState`).
Neuer Core-Service `ClobUserChannelService : BackgroundService`:
- Verbindet pro Live-Account, Auto-Reconnect mit Backoff (Muster von
`AlchemyWssClient` übernehmen).
- Publiziert Fill-Events intern (Event oder Channel), z. B.
`record OrderFillEvent(int AccountId, string TokenId, string OrderId, string Side, decimal Price, decimal Size, DateTime Ts)`.
Konsumenten im Copytrading-Modul:
- `Position.EntryPrice`/`Size` mit **echten Fill-Daten** aktualisieren
(heute: Limit-Preis als EntryPrice, Korrektur erst im 30-s-REST-Sync).
- SELL-Eskalationsleiter (Phase 0.1): Fill-Bestätigung beendet die Leiter.
- Neue Tabelle `ct_fill_log` (EF-Migration im Modul): SignalPrice, OrderPrice,
FillPrice, Latenz (Signal→Fill in ms), TraderId, AccountId, TokenId, Side.
→ Grundlage für Slippage-Statistik in Phase 3.
### 1.2 CLOB Market-Channel (Orderbücher live)
Neuer Core-Service `ClobMarketDataService`:
- Abonniert den öffentlichen `market`-Channel für eine dynamische Token-Liste
(Subscribe/Unsubscribe zur Laufzeit).
- Hält `OrderBookCache` (Best-Bid/Ask, Tiefe der obersten N Level, Timestamp).
- Interface für Konsumenten: `IOrderBookProvider.TryGetBook(tokenId, maxAgeMs)`.
- REST-Fallback `GET /book` über `PolymarketClobClient`, wenn kein Stream aktiv.
**Hinweis:** Im Modul existiert bereits ein `PolymarketWssClient` (Auto-Redeem).
Nicht verschieben/umbauen (Regression-Risiko), sondern den neuen Core-Service
parallel aufbauen; spätere Konsolidierung als separater Schritt.
### 1.3 Pre-Trade-Orderbuch-Check in der Engine
Vor jedem Live-BUY in `CopyTradingEngine.ProcessAccountOrderAsync`:
1. Buch holen (`IOrderBookProvider`, Fallback REST, Timeout ~150 ms —
bei Timeout Verhalten wie heute, nicht blockieren).
2. Checks (neue Settings in `CopyTradingAccountSettings`):
- `MaxSpreadPct` (Default z. B. 5 %): Spread größer → Skip mit Log.
- Tiefen-Check: liegt an unserem Limit-Preis genug Ask-Size für
`exactShares`? Wenn nein → Skip („Sniping-Verdacht: Liquidität bereits
konsumiert") statt teuer ins dünne Buch zu laufen.
**Akzeptanz Phase 1:** Fill-Log füllt sich mit echten Fills; TradeReasoning
zeigt Spread/Tiefe-Entscheidungen; kein messbarer Latenz-Nachteil im Hot-Path
(> 200 ms Zusatz wäre Regression).
---
## Phase 2 — SELL-Verfeinerung: Proportionalität
Heute (Proportionalitätsfilter in `CopyTradingEngine`, SELL-Pre-Flight):
verkauft der Master < 30 % seines Bestands → ignorieren; ≥ 30 % → **wir
verkaufen alles**. Information über gestaffelte Exits geht verloren.
**Ziel:** Verkaufsquote spiegeln.
1. Beim Öffnen einer Position den Master-Bestand zum Einstiegszeitpunkt
festhalten (`MasterSharesAtEntry`, im `CopyTradingState.MasterTraderPositions`
bzw. auf der Position persistieren).
2. Bei SELL-Signal: `sellRatio = signal.Size / masterSharesVorVerkauf` (wie
heute berechnet). Statt Voll-Exit: `sharesToSell = ourShares * sellRatio`.
3. Untergrenzen beachten: bleibt danach < Polymarket-Minimum (56 Shares) übrig
→ Voll-Exit statt Rest-Dust.
4. Kleiner Teilverkauf (< 10 %) weiterhin ignorieren (Rauschen von Day-Tradern),
Schwelle konfigurierbar (`MinSellRatioPct`).
5. Verkauf läuft immer über die Eskalationsleiter aus Phase 0.1.
Akzeptanz: Unit-Tests für die Ratio-Logik inkl. Dust-Grenzen; Logs zeigen
„Teilverkauf x % gespiegelt".
---
## Phase 3 — Trader-Intelligence (Auswahl automatisieren)
> Beim Copytrading entscheidet die Master-Auswahl über den Großteil des
> Ergebnisses. Diese Phase macht sie messbar und selbstkorrigierend.
### 3.1 Copy-PnL-Score („Kopierbarkeit")
Der `MasterTraderAnalyticsJob` misst heute den PnL des **Masters**. Relevanter
ist, was **wir** mit ihm verdient haben — inkl. unserer Slippage und Fees.
1. Neue Kennzahlen je Master aus `ct_`-Closed-Trades (`ICopyTradeLogRepository`,
Filter `SourceTraderId`, letzte 30 Tage):
- `CopyPnl30d`, `CopyProfitFactor` (Bruttogewinn/Bruttoverlust),
`CopyAvgPnlPerTrade`, `CopyTradeCount30d`.
- `AvgSlippagePct` aus `ct_fill_log` (Phase 1.1): Ø(FillPriceSignalPrice)/SignalPrice.
2. Felder auf `TrackedTrader` ergänzen (+ EF-Migration `mod_copytrading_trackers`),
Berechnung im `MasterTraderAnalyticsJob`, Anzeige in `MastersTradersView`.
3. **Achtung Metrik-Falle:** Winrate allein ist irreführend (Favoriten-Käufer
haben 95 % Winrate und können trotzdem negativ sein). Profit-Faktor und
Ø-PnL/Trade als primäre Sortierung in der UI.
### 3.2 Sniper-/Verhaltens-Metriken in den Analytics-Job
Portierung der Logik aus `analyze_snipers.py` (liegt im Projektroot) nach C#
in den `MasterTraderAnalyticsJob`:
1. Data-API-Activity je Master über volle 3 Tage paginieren (das Skript zeigt
das Pagination-Muster; API-Limit je Request beachten).
2. Kennzahlen: `MedianHoldMinutes`, `SellWithin5MinPct` (Anteil SELLs < 5 min
nach zugehörigem BUY), `SellCount3d`.
3. Schwellen (konfigurierbar): `SellWithin5MinPct > 50 %` → Master als Sniper
flaggen: Warn-Status in UI + Threema-Hinweis. Optional Auto-Pause (siehe 3.3).
### 3.3 Automatischer Kill-Switch je Master
Neue Modul-Settings (global, z. B. in `CopyTradingState` + Persistenz):
`AutoPauseEnabled`, `AutoPauseMinTrades` (z. B. 10), `AutoPauseDrawdownUsd`
oder `-Pct`.
Regel im Analytics-Job (läuft 2×/Tag — zusätzlich stündlicher Light-Check
sinnvoll): Copy-PnL der letzten N Trades unter Schwelle → `IsActive = false`,
`Reasoning` mit Begründung + Zeitstempel befüllen, Threema-Notification.
Reaktivierung bewusst nur manuell.
**Akzeptanz Phase 3:** UI zeigt Copy-Score-Spalten; ein simulierter
Verlust-Master wird automatisch pausiert (Test mit Demo-Daten).
---
## Phase 4 — Maker-Mode & Demo-Realismus
### 4.1 Maker-Einstieg für langsame Master
Für Master mit Haltedauern von Stunden/Tagen (SwissTony/RN1-Typ) ist der
3-Sekunden-Taker-Fill unnötig teuer (Fees + Spread). Neues Verhalten
(Flag je Trader, z. B. `Category == "HOLDER"` oder eigenes Bool `MakerEntry`):
1. BUY als GTC-Limit **auf** Best-Bid (oder Mid 1 Tick) statt über dem Ask.
2. Kein Fill nach T Minuten (konfigurierbar, z. B. 10) und Signal-Markt noch
im Preisband → auf Taker-Verhalten eskalieren oder verwerfen (Setting).
3. Fees: Maker zahlt 0 und sammelt ggf. Rebates — im Fee-Modell (0.2) abbilden.
### 4.2 Demo-Modus realistisch machen
Demo füllt heute zum Signalpreis ohne Slippage/Fees → Demo-Ergebnisse sind
systematisch geschönt und als Validierung neuer Master unbrauchbar.
Fill-Modell im Demo-Pfad der Engine:
`FillPreis = Signalpreis + halber Spread (aus IOrderBookProvider, Fallback
+1 ¢) `, Fee der Marktkategorie abziehen, beides im `ClosedTrade` ausweisen.
**Akzeptanz:** Demo- und Live-PnL desselben Masters weichen über 2 Wochen um
< 20 % relativ ab (grobe Plausibilität statt heutiger Systematik-Lücke).
---
## Offene Entscheidungen (vor Umsetzung mit Richard klären)
1. `SellFloorPct`-Default und Stufen-Timing der Eskalationsleiter (0.1).
2. `ProfitTarget`: implementieren (Empfehlung) oder Feld entfernen?
3. Auto-Pause: nur benachrichtigen oder hart deaktivieren? (Empfehlung: hart,
nachts passiert sonst genau das Falsche.)
4. Maker-Mode: als Trader-Flag oder automatisch aus `MedianHoldMinutes`
ableiten? (Empfehlung: automatisch ab z. B. Median > 60 min, manuell
überschreibbar.)
## Reihenfolge & Abhängigkeiten
```
Phase 0 (sofort, unabhängig)
└── Phase 1 (Core-Infra; parallel zu 0 möglich, Livegang nach 0)
├── Phase 2 (braucht 0.1-Leiter)
├── Phase 3 (braucht 1.1-Fill-Log für Slippage; Rest unabhängig)
└── Phase 4 (braucht 1.2-Orderbuch)
```
@@ -0,0 +1,163 @@
# Umsetzungsplan: Fable-Code-Review-Fixes (Copytrading)
> Basis: Fable-5-Review nach Umsetzung des Rentabilitätsplans (Stand 2026-07-08).
> Ausgangslage: 207 Tests grün, Build/Smoke grün. Die Logic/-Klassen sind laut Review
> sauber; die Lücken liegen im **Zusammenspiel** von SELL-Leiter, Engine und den
> Hintergrund-Services (TraderMonitorService).
## Fortschritt
-**Slice 0** IClobClient-Seam + FakeClobClient (verhaltensneutral).
-**Slice 1** K1/H2/H1: atomarer Claim, Cleanup+Engine schonen Leitern, Floor-Robustheit. 8 Tests.
-**Slice 2** K2: Startup-Reconciliation (GetOpenOrders ohne assetId = alle). 3 Tests.
-**Slice 3** K3 (System-SELL vom Ownership-Check ausgenommen + Resolved-Cache) + M5 (Demo-Score-Anzeige, stündl. Auto-Pause). 5 Tests.
-**Slice 4** H4 (RoundToTick + Dust-Abbruch), M1 (GlobalPnl im Guard), M2 (TokenId), M3-min (serverseitiges Max + lauter Fehlschlag), M4 (Parser 9999), M6 (Fees in Orders), Doku. 10 Tests.
-**Slice 5** H3: BUY-Skip während ExitPending (Entscheidung A).
-**Slice 6** SnapshotService entfernt, Demo-Balance/PnL-Reconciliation, Settings-Validierung (IsLadderConfigInverted + Load-Warnung). 3 Tests.
**Stand: 244 Tests grün, Build/Smoke grün.**
### Nachgelagerte Testabdeckung (nach dem K3-Fund)
- **Engine-Integrationstests** (`CopyTradingEngineTests`, gemockter CLOB): H3 BUY-Skip, Doppel-SELL-Guard, K3 System-Close, Fremd-Trader-Reject, H2 Cleanup-schont-Leiter (+Kontrast). Engine `_clob``IClobClient`, `ProcessAccountOrderAsync` internal.
- **⚠️ K3-Korrektur:** Der Slice-3-Fix sass am falschen Ort (downstream ~Z.643). Der echte Ownership-Check ist der frühe `inPortfolio`-Lookup (~Z.437, `p.SourceTraderId == signal.TraderId`), der System-Signale schon vorher mit early return abwies. Jetzt am richtigen Ort via `IsAuthorizedSell` **vom Engine-Test aufgedeckt**.
- **K1a-Test** (`TraderMonitorServiceTests`): Cleanup cancelt Leiter-Order nicht (aktive Leiter) bzw. cancelt sie ohne Leiter. `_clob``IClobClient`, `CleanupStaleOpenOrdersAsync` internal.
**Alle 3 kritischen + 4 hohen Bugs sind jetzt durch Tests abgesichert** (K1a/K1b/K2/K3/H1/H2/H3/H4).
### Bewusst aufgeschobene Follow-ups (Live-Verifikation/Risiko)
- **M3 Autoincrement-Migration**: `TradeId` auf DB-Autoincrement umstellen Schema-Änderung an der Trade-Persistenz, erst im Zielland live verifizieren. (M3-Minimum ist umgesetzt.)
- **PersistenceService-Dedup-Zeitfenster**: `Exists(AccountId,TokenId)` blockt legit Re-Entries; robuster Fix (z.B. OpenedAt-basiert) braucht Live-Daten Duplikat-Schutz nicht unverifiziert brechen.
- **Perf**: `UpsertLive`-Dirty-Check (Schreib-Amplifikation) und Leiter-Parallelität laut Fable bei aktueller Größe unkritisch.
- **M6/K2**: fee-signierte Orders bzw. `/data/orders` ohne asset_id sind API-gated → im Zielland verifizieren.
## Arbeitsgrundsätze (für jeden Slice)
1. **`.agents/rules/clob.md`:** vor jedem CLOB-nahen Slice ein Commit als Rollback-Punkt;
Preis-/Zustandslogik pur in `SellLogic`/`CopyTradingRisk` + neue Tests; Service-Interaktionen
(Cleanup überspringt Leiter etc.) mit kleinem **Integrationstest über gemockten CLOB-Client**.
2. Nach jedem Slice: `dotnet build` + `dotnet test` (alle grün) + `--smoke-ui` grün, dann commit+push.
3. Ein Slice = eine kohärente Einheit = ein Commit. Reihenfolge unten folgt Fables Empfehlung.
---
## Slice 0 (Prereq): Testbarkeit — `IClobClient`-Interface
**Warum zuerst:** K1/H2/K2 brauchen Integrationstests mit gemocktem CLOB. `PolymarketClobClient`
ist heute eine konkrete Klasse ohne Interface → nicht mockbar.
- Interface `IClobClient` (Core) mit den von Leiter/Reconciliation genutzten Methoden:
`PlaceOrderAsync`, `CancelOrderAsync`, `GetOpenOrdersAsync`, `CancelConflictingOrdersAsync`.
- `PolymarketClobClient : IClobClient`. DI zusätzlich `IClobClient → PolymarketClobClient`.
- `SellLadderService`/Reconciliation gegen `IClobClient` typisieren (Engine kann vorerst konkret bleiben).
- **Verhaltensneutral, keine Logikänderung.** Ermöglicht `FakeClobClient` im Testprojekt.
- Tests: keine neuen fachlichen; Build grün genügt.
---
## Slice 1: „Wer darf Leiter-Orders anfassen" (H1 + K1 + H2) 🔴🟠
Kernthema: Leiter-Order darf nur von der Leiter angefasst/gecancelt werden.
- **H1 — Atomarer Claim:** In `SellLadderService.StartLadderAsync` als ERSTES
`if (!_copyState.ExitLadders.TryAdd(key, placeholder)) return false;` → macht ALLE Aufrufer
(Engine-SELL + ProfitTarget) idempotent. Bei Fehlschlag der Order den Key wieder entfernen.
- **K1 — Cleanup überspringt Leitern:** In `TraderMonitorService.CleanupStaleOpenOrdersAsync`
Keys mit `_copyState.ExitLadders.ContainsKey(key)` überspringen (`continue`).
- **K1 — Floor-Robustheit:** In `SellLadderService.ProcessLadderAsync` am Floor NICHT dauerhaft
früh zurückkehren, sondern periodisch via `GetOpenOrdersAsync` prüfen, ob die Floor-Order noch
ruht; wenn nicht → am Floor neu platzieren (+ `PendingOrderTimestamps` refreshen).
- **H2 — Engine-Cancel schont Leiter:** Den Pre-Signal-`CancelConflictingOrdersAsync`-Aufruf der
Engine überspringen, wenn `_copyState.ExitLadders.ContainsKey(key)` (oder hinter den
ExitPending-Check verschieben).
- Tests: Integrationstest (FakeClob) — Cleanup cancelt KEINE Leiter-Order; zwei parallele
StartLadder-Aufrufe → nur eine Leiter; Floor-Order weg → Leiter platziert neu. Pure: ggf.
Floor-Recheck-Entscheidung.
---
## Slice 2: Neustart-Reconciliation (K2) 🔴
Ruhende GTC-Leiter-/Maker-Orders überleben Neustarts, der Verwaltungszustand nicht.
- Beim Modul-Start je **Live-Account** alle offenen CLOB-Orders via `GetOpenOrdersAsync` abrufen und
pauschal canceln (deterministisch; die Engine entscheidet danach sauber neu). Kein Leiter-Rebuild.
- Ort: eigener Startup-Schritt im Modul (z. B. in `TraderMonitorService`-Warmup oder als kurzer
`IHostedService`), NACH der State-Hydration, VOR dem ersten Signal-Processing.
- Umfangreiches Logging (welche Orders gecancelt).
- Tests: Integrationstest (FakeClob) — für jeden offenen Order-Eintrag wird Cancel gerufen.
---
## Slice 3: Demo-Resolution + Demo-Score (K3 + M5) 🔴🟡
Sonst ist die Demo-Validierungsphase (auf der die Zielland-Strategie beruht) wertlos.
- **K3 — System-Signale (TraderId==0) vom Ownership-Check ausnehmen:** In der Engine SELL-Pre-Flight
(`p.SourceTraderId == signal.TraderId`) den Fall `signal.TraderId == 0` zulassen (System-Close bei
Marktauflösung). Zusätzlich „bereits als resolved erkannt"-Cache, damit ein Markt nur einmal
verarbeitet wird (verhindert 30-s-Loop-Spam + API-Last).
- **M5 — Demo-Score & schnellerer Auto-Pause:** Copy-Score getrennt für Demo (Anzeige/Validierung)
und Live (Pausieren) berechnen; der Kill-Switch filtert weiterhin `!IsDemo`, aber die Demo-Kennzahlen
füllen die Spalten. Zusätzlich stündlicher Light-Check nur für die Pause-Regel (statt nur alle 12 h).
- Tests: Ownership-Ausnahme (Engine), Resolved-Cache (pure). Demo/Live-Score-Trennung ist Job-Logik.
---
## Slice 4: Kleine, klar umrissene Fixes (H4 + M1 + M2 + M3 + M4 + M6 + Doku) 🟠🟡🟢
Jeweils klein und abgegrenzt — in einem oder zwei Commits.
- **H4 — Dust-Reject-Schleife:** (a) Leiter-Preis vor der USDC-Berechnung auf Tick runden
(`Math.Round(next, 3)`, zentral in `SellLogic`); (b) Abbruch in `ProcessLadderAsync`:
`pos.Size < CopyTradingRisk.MinShares` → Leiter beenden, `ExitPending=false`, Dust loggen.
Pure Tests für Rundung + Abbruch.
- **M1 — GlobalPnl-Doppelzählung:** In `TraderMonitorService` (~Z.910 und ~Z.961) das
`GlobalPnl += realizedPnl` INNERHALB des `_processedClosures`-Guards buchen (wie in
`PollClosedAccountsAsync` bereits korrekt).
- **M2 — TokenId in Live-Close-Records:** In beiden Live-Close-Records (~Z.922-940 und ~Z.972-990)
`TokenId = removedPos.TokenId` setzen (der 0.4-Fix erwischte nur den Demo-Pfad).
- **M3 — TradeId robust:** `ClosedTrade.TradeId` auf DB-Autoincrement (`ValueGeneratedOnAdd`)
umstellen + Code-Vergabe (`GetNextTradeId`) entfernen + Migration. Eliminiert die stille
PK-Kollisions-Fehlerklasse und den teuren Full-Table-`Max()`-Startup in `Program.cs`.
(Alternative/Minimum: serverseitiges `Max()` + lauter Fehlschlag statt `catch {}`.)
- **M4 — Parser-Default:** `MongoExportParser` ProfitTarget-Fallback `50m → 9999m` (sonst schaltet
ein erneuter `--migrate-json`-Lauf Take-Profit unbeabsichtigt scharf). Pure Test.
- **M6 — Fee in signierte Orders:** An den Callsites (Engine-BUY, Leiter, PreRedeem)
`actualFeeBps` aus `FeeModel`/`MarketData.TakerFeeBps` an `PlaceOrderAsync` durchreichen.
Verifikation im Zielland, aber die Verdrahtung jetzt.
- **Doku — Stale [Description]:** `SellFloorPct` ist verdrahtet (nicht „Phase 0.1 offen");
`ProfitTarget`-Text nicht mehr „folgt in Phase 0.3". Texte aktualisieren (Richard verlässt sich drauf).
---
## Slice 5: H3 — BUY während ExitPending 🟠
Re-buyt der Master, während unsere Leiter verkauft, kauft die Engine normal zu → die Leiter verkauft
danach `pos.Size` inkl. neuer Shares zum alten Floor.
**ENTSCHEIDUNG (Richard, 2026-07-08): Variante A — BUYs skippen, solange `ExitPending`.**
Während des Ausstiegs keine Zukäufe; die Leiter verkauft die Position sauber zu Ende.
- Umsetzung: In der Engine BUY-Pre-Flight früh prüfen —
`if (account.OpenPositions.TryGetValue(signal.TokenId, out var p) && p.ExitPending) { log + return; }`.
(Spiegelt die bestehende Double-Sell-Guard-Logik, nur für den BUY-Pfad.)
- Umfangreiches Logging (verworfener BUY während aktivem Exit inkl. TokenId/TraderId).
- Tests: Engine-BUY-Pfad überspringt, solange `ExitPending`; nach Leiter-Ende (ExitPending=false)
wird ein neuer BUY wieder normal ausgeführt.
---
## Slice 6: Rest nach Gelegenheit (🟢 Perf/Doku)
- **PersistenceService-Dedup:** `Exists(AccountId, TokenId)` blockt legitime Re-Entries (HF-Alltag) →
Dedup-Schlüssel um Zeitfenster ergänzen. (Copy-Score untererfasst sonst.)
- **Demo-Balance vs. PnL:** Balance sollte `exitUsd ExitFee` gutschreiben (und der BUY die Entry-Fee
abziehen), damit Σ(Balance-Änderungen) = Σ(PnL). Aktuell driftet es um die Fees.
- **Settings-Validierung:** `MaxPriceDifference% > SellFloorPct` → Leiter startet unter dem Floor
(sofortige „Floor erreicht"-Notification). UI-Warnung/Validierung.
- **Perf — Schreib-Amplifikation:** `PollLiveAccountsAsync` `UpsertLive` je Position alle 30 s →
Dirty-Check (nur bei Änderung) oder Batch.
- **Perf — Leitern seriell:** `ProcessLadderAsync` pro Tick seriell → begrenzte Parallelität + Timeout.
- **Totcode:** `services/SnapshotService.cs` entfernen (nirgends registriert) oder bewusst reaktivieren.
---
## Empfohlene Reihenfolge (Fable)
`Slice 0` (Test-Infra) → `Slice 1` (K1+H2+H1) → `Slice 2` (K2) → `Slice 3` (K3+M5) →
`Slice 4` (H4/M1/M2/M3/M4/M6/Doku) → `Slice 5` (H3, nach Entscheidung) → `Slice 6` (Rest).
**Als korrekt bestätigt (nicht anfassen):** Logic/-Klassen sauber/verhaltenstreu; ExitPending
EF-ignoriert; TotalFees gemappt; closed_trades-Indizes vorhanden; SellLadderService als
Singleton+Hosted (eine Instanz); Copy-Score-Find serverseitig; SELL-Spam-Blockade seitensensitiv.
@@ -0,0 +1,187 @@
# Umsetzungsplan: Modul „BundleArbitrage" (Intra-Market- & NegRisk-Arbitrage)
> Stand: 2026-07-06
> Ziel: Neues Strategiemodul, das Preissummen-Anomalien innerhalb von
> Polymarket erkennt und handelt: YES + NO < $1.00 (binäre Märkte) und
> Summen-Verletzungen in NegRisk-Multi-Outcome-Märkten.
> Reihenfolge: Nach/parallel zu MarketMaking — nutzt dieselbe Orderbuch-
> Infrastruktur. **Harte Voraussetzung:** Phase 1 (Marktdaten-Fundament) aus
> `UMSETZUNGSPLAN-CopyTrading-Verbesserungen.md`.
> **Wichtig:** Dieses Modul startet bewusst als reines Mess-Modul
> (Detection-only). Ob Execution gebaut wird, entscheidet die Messphase.
---
## 0. Strategie-Hintergrund & ehrliche Einordnung
**Mechanik:**
- **Binär:** Kostet YES + NO zusammen < $1.00 (beide zum Ask kaufbar),
ist der Kauf beider Seiten ein garantierter Gewinn: Das Paar zahlt bei
Resolution sicher $1.00 aus — oder kann on-chain sofort zu $1.00 USDC
zusammengelegt werden (CTF `mergePositions`).
- **NegRisk (Multi-Outcome, genau ein Gewinner):** Summe aller YES-Asks < $1.00
→ alle YES kaufen (eines zahlt aus). Komplementär: Überteuerte Summen über
die NO-Seite bzw. NegRisk-Konvertierungen handeln.
**Ehrliche Einordnung (Stand 2026):** Auf den großen Märkten ist das ein
HFT-Spiel — Fenster von Sekunden, dominiert von spezialisierten Bots; die
Taker-Fees seit März 2026 haben viele kleine Anomalien zusätzlich unprofitabel
gemacht. **Die Chance liegt im Long Tail** (kleine/neue Märkte, auf die die
großen Bots nicht schauen) und als **Beifang** der ohnehin laufenden
Orderbuch-Streams des MarketMaking-Moduls. Deshalb: erst messen, dann bauen.
**Fee-Beachtung:** Als Taker fallen je Leg Fees an (kategorieabhängig,
01,8 %). Ein Bundle mit 2 ¢ Brutto-Marge kann nach Fees negativ sein.
Die Profitrechnung muss Fees je Leg von Anfang an enthalten. Maker-seitige
Ausführung (ein Leg ruht als Limit) ist fee-frei, aber nicht atomar.
---
## 1. Architektur-Einbettung
Neues Projekt `src/PolyTrader.Modules.BundleArbitrage/` als `IPolyTraderModule`
(`Name = "BundleArbitrage"`, `DbPrefix = "ba_"`), Registrierung in `Program.cs`.
**Eigener Polymarket-Account** (gleiche Begründung wie in den anderen
Modul-Plänen; kann sich in v1 den Account mit MarketMaking teilen, sofern
die Inventar-Buchführung getrennt bleibt — Empfehlung: eigener Account,
sobald Execution live geht).
### Persistenz
| Tabelle | Inhalt |
|---|---|
| `ba_opportunities` | Jede erkannte Anomalie: Zeitpunkt, Markt/Event, Legs mit Preisen & ausführbarer Size, Brutto-/Netto-Marge (nach Fees), Lebensdauer (wann verschwunden) |
| `ba_executions` | Ausgeführte Bundles: Legs, Fills, Slippage, Ergebnis |
| `ba_settings` | Schwellen, Size-Limits, Modus (Detect/Execute) |
Die Lebensdauer-Messung („wie lange war die Anomalie ausführbar?") ist der
wichtigste Datenpunkt der Messphase — sie entscheidet, ob unsere
Ausführungslatenz überhaupt konkurrenzfähig ist.
---
## 2. Komponenten
### 2.1 `ArbScannerService : BackgroundService` — Detection
Zwei Datenpfade:
1. **Hot Set (WSS):** Für die vom `ClobMarketDataService` (Core) ohnehin
gestreamten Bücher (MarketMaking-Märkte + Top-Volumen-Märkte) wird bei
jedem Book-Update die Summenprüfung getriggert (< 1 ms, pure Funktion).
2. **Long-Tail-Sweep (REST):** Zyklischer Scan über aktive Märkte
(Gamma-API-Liste, dann CLOB `GET /book` bzw. Batch-Preis-Endpoints —
verfügbare Batch-Endpoints bei Umsetzung in der Doku prüfen).
Rate-Limits respektieren (Batching + Delays wie im
`TraderMonitorService`-Muster); Sweep-Frequenz Setting (z. B. alle 60 s
für 500 Märkte, priorisiert nach Volumen/Neuheit).
**Prüf-Logik (pure, getestete Klasse `BundleMath`):**
- Binär: `bestAskYes + bestAskNo + FeeYes + FeeNo < 1.00 MinMarginPct`.
Ausführbare Size = min(AskSize beider Seiten), ggf. über mehrere Book-Level
kumuliert (Level-2-Sweep-Rechnung).
- NegRisk: `Σ bestAskYes_i + Σ Fees < 1.00 MinMarginPct` über alle Outcomes
eines NegRisk-Events (Event-Gruppierung über Gamma-API; `NegRisk`-Flag
existiert bereits in `MarketData`).
- Jede erkannte Anomalie → `ba_opportunities`; bei Verschwinden (nächstes
Update unterschreitet Schwelle) Lebensdauer nachtragen.
### 2.2 Mess-Auswertung (Phase BA-1, entscheidungsrelevant)
Report (UI-Tab + wöchentlicher Threema-Report):
- Anomalien/Tag nach Marge-Bucket (0,51 %, 12 %, > 2 % netto).
- Verteilung ausführbare Size und Lebensdauer.
- Erwarteter Monatsertrag bei angenommener Erfolgsquote X % =
Σ(Netto-Marge × min(Size, unser Limit)) über gefangene Fenster.
**Go/No-Go-Kriterium für Execution:** erwarteter Ertrag > Entwicklungs- und
Kapitalkosten; realistisch fangbare Fenster (Lebensdauer > unsere Latenz,
konservativ ≥ 23 s).
### 2.3 `ArbExecutionService` — nur nach Go-Entscheidung
1. **Beide Legs gleichzeitig** als IOC-artige Orders senden (CLOB-Ordertypen
FOK/FAK bei Umsetzung in der Doku verifizieren; `PolymarketClobClient`
ggf. erweitern). Preis = erkannter Ask + kleiner Puffer, Size = min-Leg.
2. **Single-Leg-Risiko** (ein Leg füllt, das andere nicht) ist das
Kernproblem — Behandlungsreihenfolge:
a) Sofortiger Retry des offenen Legs (bis Preis `1.00 Fees MinMargin/2`).
b) Kein Fill → offenes Leg als GTC-Maker-Order zum Break-even-Preis stellen.
c) Timeout (Setting, z. B. 10 min) → Leg über Eskalationsleiter abbauen
(Muster aus Copytrading-Plan Phase 0.1) und Verlust in `ba_executions`
verbuchen. `MaxSingleLegLossUsd`-Tageslimit als Kill-Switch.
3. Size-Limits: `MaxUsdPerBundle` (Start 1025), `MaxOpenBundles`,
Tagesbudget.
4. `.agents/rules/clob.md` beachten — jede CLOB-Client-Erweiterung mit
Backup/Commit und Mehrfach-Review.
### 2.4 Kapital-Recycling: CTF `mergePositions` (Phase BA-4)
Ohne Merge bindet jedes Bundle Kapital bis zur Resolution (bei kurzlaufenden
Märkten oft akzeptabel — Priorisierung im Scanner auf EndDate < 7 Tage
umgeht das Problem anfangs).
On-Chain-Merge: YES + NO gleicher Size → $1.00 USDC sofort, via
ConditionalTokens `mergePositions(...)`; NegRisk-Sets über den
NegRisk-Adapter. Implementierung teilt sich Infrastruktur mit dem
Auto-Redeem des ResolutionFarming-Moduls (Phase RF-4) — **gemeinsamen
Core-Baustein `OnChainCtfService` bauen**, nicht zweimal implementieren.
Contract-Adressen/ABI aus https://docs.polymarket.com (Developer/CTF)
verifizieren; Gas (POL) -Handling und Balance-Warnung wie im RF-Plan.
### 2.5 UI
- Tab „Live-Anomalien": aktuelle Opportunities mit Netto-Marge/Size.
- Tab „Messung": Statistik-Report aus 2.2.
- Tab „Executions": Bundles, Single-Leg-Vorfälle, PnL.
- Tab „Settings": Schwellen, Modus-Schalter Detect/Execute (Default: Detect).
---
## 3. Phasen & Akzeptanzkriterien
### Phase BA-1: Detection-only (24 Wochen Messung)
- Scanner (Hot Set + Long-Tail-Sweep), `BundleMath` mit Unit-Tests
(inkl. Fee-Rechnung, Level-2-Kumulation, NegRisk-Summen),
`ba_opportunities`-Logging, Mess-Report.
- Akzeptanz: App baut & läuft; Report nach 2 Wochen vollständig;
dokumentierte Go/No-Go-Empfehlung.
### Phase BA-2: Execution klein (nur bei Go)
- IOC-Doppel-Leg, Single-Leg-Behandlung, Size-Limits, Kill-Switch.
- Zunächst nur binäre Märkte (NegRisk-Execution ist komplexer → BA-3).
- Akzeptanz: ≥ 20 Bundles ausgeführt; Single-Leg-Quote < 20 %;
Netto-PnL nach Fees > 0.
### Phase BA-3: NegRisk-Execution
- Multi-Leg-Bundles (N Outcomes), strengere Size-/Slippage-Grenzen
(mehr Legs = mehr Single-Leg-Risiko).
### Phase BA-4: `OnChainCtfService` (Merge) — Kapital-Recycling
- Gemeinsam mit ResolutionFarming RF-4 (Redeem) als ein Core-Baustein.
- Testmarkt/Kleinstbetrag zuerst; Akzeptanz: Bundle → USDC ohne manuellen
Eingriff, USDC-Delta verifiziert.
---
## 4. Risiken & Gegenmaßnahmen
| Risiko | Gegenmaßnahme |
|---|---|
| Anomalien existieren, sind aber in < 1 s weg | Messphase BA-1 entscheidet VOR Entwicklungsaufwand für Execution |
| Single-Leg-Exposure | IOC-Orders, Retry-Kaskade, Tages-Verlustlimit, kleine Bundles |
| Fees fressen Marge | Netto-Rechnung inkl. Fees je Leg von Anfang an; `MinMarginPct` konservativ (Start ≥ 1 %) |
| Rate-Limits durch Long-Tail-Sweep | Batching, Priorisierung, Sweep-Frequenz drosseln; API-Fehlerquote überwachen |
| Stale-Book-Falsch-Signale | Max-Age-Check auf Book-Daten (`TryGetBook(maxAgeMs)`); Anomalie erst nach 2 aufeinanderfolgenden Bestätigungen |
| On-Chain-Merge-Fehler | Separater Baustein, Testmarkt, clob.md-Regeln, Balance-Verifikation |
## 5. Offene Entscheidungen
1. `MinMarginPct` (netto, nach Fees) für Detection-Logging (Empfehlung 0,5 %)
vs. Execution (Empfehlung ≥ 1 %).
2. Long-Tail-Sweep-Umfang (alle aktiven Märkte vs. Top-N + Neue) — abhängig
von beobachteten Rate-Limits.
3. Account-Frage: mit MarketMaking teilen oder eigener (Empfehlung: eigener,
sobald BA-2 startet).
4. Priorität von BA-4 (Merge): Bei Fokus auf kurzlaufende Märkte zunächst
verzichtbar — Kapitalbindung von Tagen ist bei kleinen Größen tragbar.
@@ -0,0 +1,200 @@
# 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`)
> aus `UMSETZUNGSPLAN-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:
1. Reward-berechtigte Märkte über Gamma-/CLOB-API listen (Felder: Reward-Pool/
Rate, `rewardsMaxSpread`, `rewardsMinSize` — Feldnamen verifizieren).
2. 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.
3. 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.100.90 (Extrempreise = asymmetrisches Inventarrisiko).
4. 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:
1. **Zielquote:** Bid und Ask symmetrisch um den Midpoint, Abstand
`QuoteSpreadTicks` (Setting), immer **innerhalb** des Reward-Max-Spreads;
Size ≥ Reward-Min-Size (Setting `QuoteSizeUsd`, initial klein).
2. **Requote-Trigger:** Midpoint-Bewegung > Schwelle (z. B. 1 Tick), eigene
Order gefüllt, Reward-Fenster verletzt. Requote = Cancel + neue Order über
`PolymarketClobClient`.
3. **Churn-Begrenzung:** Mindest-Ruhezeit zwischen Requotes (z. B. 35 s),
Hysterese (nicht bei jedem Tick nachziehen) — API-Rate-Limits und
Order-Spam vermeiden.
4. **Fill-Verarbeitung:** über `ClobUserChannelService` (Echtzeit). Nach Fill:
Inventar aktualisieren, Gegenquote anpassen (siehe 2.3).
5. 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
1. Inventar je Markt = Netto-Shares (YES-äquivalent) × Preis.
2. **Skew:** Bei wachsendem Inventar Quotes asymmetrisch verschieben
(Kaufseite weiter weg, Verkaufsseite näher/attraktiver), Faktor
proportional zu `Inventar / MaxInventoryUsd`.
3. **Limits (Settings je Markt + global):**
- `MaxInventoryUsd` je 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.
4. **Exit vor Resolution:** Ab `ExitHoursBeforeEnd` (Default 48 h) Reduce-Only,
ab 24 h aktiver Abbau (Maker-seitig, notfalls Taker mit Verlust-Deckel).
5. **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`
1. Tägliche Reward-/Rebate-Eingänge erkennen (USDC-Transfers auf die Wallet
via Data-API/Alchemy) und `mm_daily_pnl` zuordnen.
2. Tagesabrechnung: `Rewards + Rebates + SpreadPnL + InventarPnL(mark-to-mid)
Verluste = Netto`. Threema-Tagesreport.
3. 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`/`ClobUserChannelService`
laufen 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 12 ruhigen Märkten
- Eigener Account, kleines Kapital (z. B. 300500 USDC), `QuoteSizeUsd`
knapp über Reward-Min-Size, 12 langlaufende Politik-/Geopolitik-Märkte.
- Akzeptanz nach 24 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
1. Startmärkte (Empfehlung: 12 langlaufende Politik-/Geopolitik-Märkte mit
mittlerem Volumen — genug Reward-Pool, wenig Newsflow).
2. `QuoteSizeUsd`/Kapital für MM-3.
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.)
@@ -0,0 +1,212 @@
# Umsetzungsplan: Modul „ResolutionFarming" (Favoriten nahe Auflösung)
> Stand: 2026-07-06
> Ziel: Neues Strategiemodul, das systematisch unterbewertete Favoriten
> (~9098 ¢) in bald auflösenden Märkten kauft, bis zur Resolution hält und
> automatisch redeemt.
> Reihenfolge: **Erstes neues Strategiemodul** (geringster Infrastrukturbedarf,
> validiert die Modul-Architektur über Copytrading hinaus).
> Voraussetzung: Phase 0 + 0.2 (Fee-Modell) aus
> `UMSETZUNGSPLAN-CopyTrading-Verbesserungen.md`. Phase 1 (Orderbuch) ist
> hilfreich, aber nicht zwingend für den Start.
---
## 0. Strategie-Hintergrund (Warum das funktioniert)
Auswertungen der Polymarket-Handelsdaten zeigen ein **Favorite-Longshot-
Reversal**: Outcomes mit hoher Wahrscheinlichkeit sind systematisch
*unterbewertet* (Retail überschätzt Longshots und drückt damit den Favoriten-
Preis). Ein 95-¢-Favorit gewinnt im Schnitt öfter als in 95 % der Fälle.
25 % Marge in 2448 h ergibt hohe annualisierte Renditen — **sofern das
Tail-Risiko diszipliniert gemanagt wird**: Ein verlorener 95-¢-Trade
vernichtet ~19 gewonnene. Das Risikomodell IST die Strategie.
Interner Kontext: Die profitabelsten kopierten Master (Typ „SwissTony"/„RN1")
machen genau das — hunderte BUYs, nie SELLs, Auflösung abwarten. Dieses Modul
internalisiert die Strategie und eliminiert die Copy-Latenz und die
Fremdbestimmung der Marktauswahl.
**Fees (seit März 2026):** Taker-Fees je Kategorie (Sports ~0,75 %, Politik
~1,0 %, Krypto ~1,8 %, Geopolitik 0 %) — bei 25 % Brutto-Marge ist die
Kategorie-Wahl entscheidend. Maker-Einstieg (Limit ins Buch) zahlt 0 Fees.
---
## 1. Architektur-Einbettung
Neues Projekt `src/PolyTrader.Modules.ResolutionFarming/` (Class Library,
net8.0-windows), Registrierung als `IPolyTraderModule` analog
`CopyTradingModule` (`Name = "ResolutionFarming"`, `DbPrefix = "rf_"`),
Einbindung in `Program.cs` der App.
### ⚠️ Grundsatzentscheidung: Eigener Polymarket-Account je Strategiemodul
**Dringende Empfehlung:** Das Modul handelt über einen **eigenen Account**
(Multi-Account-Support existiert im Core / `AccountState`).
Begründung: Der `TraderMonitorService` des Copytrading-Moduls synct **alle**
Wallet-Positionen eines Accounts in `account.OpenPositions`, würde
ResolutionFarming-Positionen „adoptieren" (Master-Zuordnungs-Fallbacks),
in seine Limits (PerMarket/PerMaster/Zeitfenster) einrechnen und ggf.
Auto-Redeem-/Cleanup-Logik darauf anwenden. Saubere Trennung über getrennte
Wallets vermeidet diese gesamte Konfliktklasse zur Laufzeit **und**
buchhalterisch (PnL je Strategie sauber messbar).
In der UI/Settings des Moduls: Zuordnung `AccountId ↔ Modul` mit Warnung,
wenn derselbe Account auch im Copytrading aktiv ist.
### Persistenz (EF Core / Pomelo / MySQL, eigener DbContext analog `CopyTradingDbContext`)
| Tabelle | Inhalt |
|---|---|
| `rf_settings` | Modul-Settings je Account (Preisband, Budgets, Limits) |
| `rf_candidates` | Scanner-Ergebnisse (Markt, Preis, Score, Filtergründe) — auch abgelehnte, für spätere Kalibrierung |
| `rf_positions` | Offene Farming-Positionen (TokenId, Entry, Size, EndDate, ClusterKey, Status) |
| `rf_closed_trades` | Abgeschlossene Trades inkl. Fees, Redeem-Infos |
Zusätzlich schreibt das Modul in den generischen Core-Trade-Log
(modulübergreifendes Dashboard).
---
## 2. Komponenten
### 2.1 `MarketScannerJob : BackgroundService`
Alle 1015 Minuten (JobManager-Registrierung wie `MasterTraderAnalyticsJob`,
manuell triggerbar):
1. Gamma-API: aktive Märkte mit `endDate < now + MaxHoursToResolution`
(Default 48 h), nicht closed. Bestehenden `PolymarketApiService` erweitern
(Query-Parameter für endDate-Fenster; Endpoint-Details bei Umsetzung aus
https://docs.polymarket.com verifizieren).
2. Je Markt den Favoriten bestimmen (Outcome mit höchstem Preis). Preisquelle:
CLOB Midpoint/Book (REST `GET /book` bzw. `IOrderBookProvider`, falls
Phase 1 des Copytrading-Plans schon umgesetzt).
3. Filterkette (jeder Reject wird mit Grund in `rf_candidates` geloggt):
- Preisband: `MinPrice ≤ ask ≤ MaxPrice` (Default 0.900.98).
- Liquidität: Ask-Tiefe am Zielpreis ≥ geplante Ordergröße × Faktor;
zusätzlich Markt-Volumen/Liquiditätsfelder der Gamma-API als Grobfilter.
- Kategorie-Whitelist (Default: Sports, Geopolitik, Politik; **Krypto
ausschließen** — 1,8 % Fee frisst die Marge; keine 15-Min-/Stunden-Märkte).
- Netto-Edge-Check: `(1 ask) Fee(ask, Kategorie) ≥ MinEdgePct`
(Default z. B. 1,5 %).
- Blacklist-Mechanismus (Slugs/Tags), z. B. für Marktarten mit
Resolution-Streitigkeiten (UMA-Disputes).
4. Kandidaten mit Score in `rf_candidates` schreiben; Anzeige in der Modul-UI.
### 2.2 Risiko-Engine (pure, testbare Klasse `FarmingRiskEngine`)
Settings je Account (`rf_settings`):
| Setting | Default | Bedeutung |
|---|---|---|
| `MaxPerMarketUsd` | 25 | Max. Einsatz je Markt |
| `MaxPerClusterPct` | 10 % | Max. Anteil der Bankroll je **Ereignis-Cluster** |
| `MaxTotalExposurePct` | 60 % | Max. Gesamteinsatz in offenen Positionen |
| `MaxNewPositionsPerDay` | 20 | Drosselung |
| `MinEdgePct` | 1.5 % | Netto-Edge nach Fees |
| `DailyLossKillSwitchUsd` | konfig. | Tagesverlust → Modul pausiert + Threema |
**Cluster-Definition (kritisch!):** 20 Fußballspiele desselben Spieltags sind
keine 20 unabhängigen Wetten. ClusterKey ableiten aus Event-/Series-Slug der
Gamma-API (z. B. Liga+Datum, Turnier, Wahl-Event). Korrelierte Favoriten
(z. B. „Kandidat X gewinnt" + „Partei von X gewinnt") teilen einen Cluster.
Erste Version: Heuristik über Event-Slug; Verfeinerung später.
### 2.3 `FarmingExecutionService`
1. Einstieg **Maker-first**: GTC-Limit auf Best-Bid bzw. Mid 1 Tick
(0 Fees). Kein Fill nach T Minuten (Default 15) → Entscheidung per Setting:
Taker-Fill (wenn Netto-Edge auch mit Fee noch ≥ MinEdge) oder verwerfen.
2. Order-Verwaltung über `PolymarketClobClient` (Core), Tracking analog
`PendingOrderTimestamps`-Muster des Copytrading-Moduls.
3. Positionen in `rf_positions` + Core-Positions-Sync gegen die Wallet
(Data-API `positions` — Muster aus `TraderMonitorService.PollLiveAccountsAsync`
übernehmen, aber schlanker: kein Master-Mapping nötig).
### 2.4 `ResolutionMonitorJob` + `AutoRedeemService`
1. Monitor: prüft offene `rf_positions` gegen Resolution
(`PolymarketApiService.CheckMarketResolutionAsync` existiert bereits).
2. **On-Chain-Auto-Redeem** (heute im gesamten Projekt nur manuell — dieser
Baustein nützt auch dem Copytrading):
- Gewinner-Shares einlösen via ConditionalTokens-Contract auf Polygon
(`redeemPositions(...)`); für NegRisk-Märkte über den NegRisk-Adapter.
**Contract-Adressen und Aufrufparameter bei Umsetzung zwingend aus der
offiziellen Doku verifizieren** (https://docs.polymarket.com,
Developer-Sektion CTF/NegRisk).
- Implementierung: Nethereum-Paket ODER Raw-RPC über die vorhandene
Alchemy-Anbindung; Signing mit dem Account-PrivateKey (liegt in
`AccountState`).
- Gas: Wallet braucht POL; Balance-Check + Threema-Warnung bei Unterdeckung.
- Retry mit Backoff; Erfolg = USDC-Balance-Delta verifiziert.
- `.agents/rules/clob.md` gilt hier besonders: On-Chain-Signing ist
hochkritisch — zuerst mit Kleinstbetrag auf einem Testmarkt verifizieren.
3. Übergangslösung bis 2.4 fertig: PreRedeem-artiger Verkauf (GTC-Limit 0.99+)
oder manueller Redeem — das Modul funktioniert auch ohne On-Chain-Teil,
bindet dann nur Kapital länger.
### 2.5 UI (`RegisterUi`, ein Fenster mit Tabs analog `CopyTradingMainForm`)
- Tab „Kandidaten": aktueller Scan mit Filtergründen (auch Rejects).
- Tab „Positionen": offene Farming-Positionen, Cluster-Auslastung, Countdown.
- Tab „Historie/Statistik": Winrate je Preisband (Kalibrierung!), Netto-PnL,
Fees, Redeem-Status.
- Tab „Settings": PropertyGrid auf `rf_settings` (Muster `AccountSettingsView`).
---
## 3. Phasen & Akzeptanzkriterien
### Phase RF-1: Modul-Skelett + Scanner (read-only)
- Projekt, Modul-Registrierung, DbContext + Migration, Scanner-Job, UI-Tab
„Kandidaten". **Keine Order-Platzierung.**
- Akzeptanz: App baut & startet mit Modul; Scanner liefert plausible
Kandidaten; Rejects nachvollziehbar geloggt; 1 Woche Kandidaten-Sammlung.
### Phase RF-2: Demo-Betrieb (4 Wochen)
- Execution im Demo-Modus (realistisches Fill-Modell: Ask-Preis + Fee,
siehe Copytrading-Plan Phase 4.2). Risiko-Engine aktiv.
- Akzeptanz/Go-Kriterium für Live: Kalibrierungstabelle zeigt
`realisierte Winrate je Preisband > Preisband-Mitte` und
Netto-Edge nach Fees > 0 über ≥ 100 Demo-Trades.
### Phase RF-3: Live klein
- Eigener Account, kleines Budget (z. B. 200500 USDC), `MaxPerMarketUsd` 510.
- Kill-Switch + Threema-Reporting (Tageszusammenfassung) aktiv.
- Akzeptanz: 2 Wochen Live ohne Ausführungsfehler; Live-Ergebnis im Rahmen
der Demo-Erwartung.
### Phase RF-4: Auto-Redeem on-chain
- Wie 2.4; zuerst Testmarkt/Kleinstbetrag, dann aktivieren.
- Akzeptanz: Gewinner-Position wird ohne manuellen Eingriff zu USDC.
### Phase RF-5: Kalibrierung & Skalierung
- Scoring von Heuristik auf Daten umstellen: historische Winrate je
Preisband × Kategorie aus `rf_candidates`/`rf_closed_trades` (+ optional
öffentliche Polymarket-Historien-Datensätze) → nur Bänder/Kategorien mit
nachgewiesenem Edge handeln. Budget stufenweise erhöhen.
---
## 4. Risiken & Gegenmaßnahmen
| Risiko | Gegenmaßnahme |
|---|---|
| Tail-Event (Favorit verliert) | Cluster-Limits, MaxPerMarket, Diversifikation über Kategorien |
| Korrelierte Cluster falsch geschnitten | Konservative Cluster-Heuristik, Review der Cluster in der UI |
| Resolution-Disputes (UMA) | Blacklist strittiger Marktarten; nur klare, objektiv auflösbare Märkte |
| Fee-Änderungen | Fee je Trade persistieren, MinEdge-Check dynamisch |
| Konflikt mit Copytrading-Sync | Eigener Account (Abschnitt 1) |
| On-Chain-Redeem-Fehler | Separate Phase, Testmarkt zuerst, Balance-Verifikation, clob.md-Regeln |
## 5. Offene Entscheidungen
1. Eigener Account: neuer Polymarket-Account nötig — wer legt ihn an, wie viel
Startkapital?
2. Preisband-Default (0.900.98) und `MinEdgePct` — mit Demo-Daten validieren.
3. Nethereum vs. Raw-RPC für On-Chain-Calls (Empfehlung: Nethereum, weniger
Fehlerfläche beim ABI-Encoding).
4. Taker-Fallback beim Einstieg erlauben oder strikt Maker-only?
@@ -0,0 +1,361 @@
# Umsetzungsplan: Modularisierung PolyTraderSharp
> Stand: 2026-07-01
> Ziel: Umbau des monolithischen WinForms-Copytraders in ein modulares System
> mit einem schlanken **Core** und unabhängigen **Modulen**. Erstes Modul: **Copytrading**.
---
## 1. Leitprinzipien
1. **Core kennt keine Module.** Der Core stellt nur Basis-Infrastruktur bereit
(Host, DB/Persistenz, Settings, Jobs, Logging, API-Clients, Benachrichtigungen,
Modul-Contract). Er hat **keine** Referenz auf irgendein Modul.
2. **Module hängen nicht voneinander ab.** Jedes Modul referenziert nur den Core.
Ein Modul kennt kein anderes Modul. Dies wird durch getrennte Projekte
**zur Compile-Zeit erzwungen**.
3. **Jede Phase lässt die App lauffähig und baubar zurück.** Kein „Big Bang".
Nach jeder Phase: Debug-Build grün, App startet, Copytrading funktioniert.
4. **WinForms bleibt.** Die GUI-Anforderung ist fix. Module tragen ihre eigenen
UI-Tabs zur Shell bei.
5. **Sicherheit vor Geschwindigkeit beim Refactoring.** CLOB-Integration ist
hochkritisch (siehe `.agents/rules/clob.md`) bei Berührung besonders sorgfältig,
jede Änderung mehrfach prüfen. Rollback jederzeit über Git möglich.
---
## 2. Zielarchitektur
### 2.1 Solution-Struktur (Multi-Projekt)
```
PolyTraderSharp.sln
├── PolyTrader.Core (Class Library, net8.0-windows)
│ • Generic Host / Bootstrap-Infrastruktur
│ • Persistenz: Repository-Interfaces + Implementierung (EF Core)
│ • Settings (appsettings.json + IOptions) + Core-Settings-Sektion
│ • JobManager, Logging (TerminalLogger / ILogger-Sink)
│ • Polymarket-Infrastruktur: PolymarketApiService, PolymarketClobClient,
│ PolymarketWssClient, AlchemyWebsocketService
│ • Querschnitt: MullvadVpnService, ThreemaService
│ • Eigene Trading-Accounts (AccountState) — die Konten, mit denen WIR traden
│ • Generischer Trade-Log (modulübergreifend auswertbar)
│ • Gesamt-Dashboard (Overview über alle Module)
│ • Core-State (generisch): MarketCache, globale Betriebsschalter
│ • IPolyTraderModule-Contract + Modul-Registry
├── PolyTrader.Modules.CopyTrading (Class Library, net8.0-windows)
│ • TraderMonitorService (Signalquelle)
│ • CopyTradingEngine (Ausführung)
│ • MasterTraderAnalyticsJob, TraderAnalyticsJob
│ • Models: TrackedTrader (kopierte Master-Trader), CopySignal,
│ CopyTradeRecord, TraderAnalyticsResult, MasterTraderHistoryRecord
│ • Copytrading-State: Traders (Master), MasterTraderPositions,
│ PendingOrderTimestamps, TraderAnalyticsCache
│ • Channels: CopySignal, ClosedTrade
│ • Eigener Copytrading-Trade-Log (Detail-Auswertung kopierter Trades,
│ zusätzlich zum generischen Core-Log)
│ • Eigene UI-Tabs (Master/Slave-Verwaltung, Modul-Analyse, Closed Trades)
│ • Eigene Modul-Settings-Sektion
│ • CopyTradingModule : IPolyTraderModule
├── PolyTrader.App (WinForms .exe, net8.0-windows)
│ • Program.cs: Host-Bootstrap, lädt Core + registrierte Module
│ • Shell-Form (frm_main reduziert auf Rahmen: Terminal, Jobs, Settings-Tab)
│ • Referenziert Core + alle aktiven Module
└── PolyTrader.Tests (xUnit, optional — spätere Phase)
• Risk-/Entscheidungslogik des Copytrading-Moduls
```
### 2.2 Modul-Contract (Entwurf)
```csharp
public interface IPolyTraderModule
{
string Name { get; } // "CopyTrading"
string DbPrefix { get; } // Namespace für DB-Objekte, z.B. "ct_"
void RegisterServices(IServiceCollection services, IConfiguration config);
void RegisterUi(IModuleUiHost uiHost); // Modul hängt seine Tabs ein
Task StartAsync(CancellationToken ct); // läuft NACH Core-Hydration
Task StopAsync(CancellationToken ct);
}
```
- **Discovery:** Die App registriert Module explizit in `Program.cs`
(`services.AddPolyTraderModule<CopyTradingModule>()`). Kein Runtime-Assembly-Scanning
(bewusst einfach gehalten; kann später zum Plugin-System ausgebaut werden).
- **Feature-/Lizenz-Gating:** `IPolyTraderModule` ist die natürliche Schnittstelle,
um Module später per Lizenz zu aktivieren/deaktivieren (vgl. `lizenssystem.md`).
### 2.3 State-Aufteilung
`TradingState` wird zerlegt:
| Feld | Ziel |
|------|------|
| `MarketCache` | **Core** (generischer Markt-Cache) |
| `GlobalTradingPaused`, `LiveTradingMode`, `DemoTradingMode` | **Core** (globale Betriebsschalter) |
| `Accounts` (unsere eigenen Trading-Accounts, `AccountState`) | **Core** — die Konten, mit denen WIR traden; modulübergreifend nutzbar |
| `Traders` (kopierte Master-Trader, `TrackedTrader`) | **CopyTrading-Modul** |
| `MasterTraderPositions`, `PendingOrderTimestamps`, `TraderAnalyticsCache`, `TotalCopyTrades`, `GlobalPnl` | **CopyTrading-Modul** |
> Entschieden (2026-07-01): Eigene Trading-Accounts liegen im **Core** (auch künftige
> Module handeln über dieselben Konten). Die **kopierten** Master-Trader (`TrackedTrader`)
> sind ein Copytrading-Konzept und liegen im **Modul**.
### 2.4 Trade-Logging (zweistufig)
Zwei unabhängige, parallel geführte Logs:
1. **Generischer Core-Trade-Log** (`TradeRecord` + `ITradeLogRepository`):
modulneutrale Felder (ModulName, AccountId, Markt, Side, Entry/Exit, PnL, Zeiten,
ExitReason). Ermöglicht die **modulübergreifende** Gesamtauswertung. Jedes Modul,
das Trades ausführt, schreibt hier einen Eintrag.
2. **Copytrading-spezifischer Log** (`CopyTradeRecord`, im Modul): erweitert die
generischen Felder um Copytrading-Details (`SourceTraderId`, `SourceTraderName`,
Master-Adresse, Signal-Herkunft) für die **detaillierte** Copytrading-Analyse.
Beim Schließen eines kopierten Trades schreibt das Modul **beides**: einen generischen
Eintrag in den Core-Log und einen Detaileintrag in seinen eigenen Log.
### 2.5 Dashboard & Analyse
- **Core-Gesamt-Dashboard:** Overview über alle Module (aggregierte PnL, Kontostände,
offene Positionen, grobe Kennzahlen je Modul) — gespeist aus dem generischen Core-Log.
- **Modul-Analyse:** Jedes Modul liefert seine eigene Detailansicht (Copytrading:
Trader-Winrates, kopierte Trades, Master-Performance) — gespeist aus dem Modul-Log.
### 2.6 Settings
- **Core-Settings-Sektion:** globale/Infrastruktur-Einstellungen (DB, VPN, Threema,
Betriebsschalter).
- **Modul-Settings-Sektion:** jedes Modul trägt seine eigene Sektion zum Settings-Tab bei
(analog zu den UI-Tabs), registriert über den `IPolyTraderModule`-Contract.
- **API-Keys sind Modul-Settings:** Alchemy-/Polymarket-WSS-Keys wandern von der globalen
`ServerSettings` in die jeweilige Modul-Settings-Sektion (siehe 2.7).
### 2.7 Streaming / WebSocket-Architektur *(Entscheidung 2026-07-01)*
**Prinzip:** Der **Core stellt die WSS-Verbindungs-Klasse als wiederverwendbare Fähigkeit**
bereit — **keinen** geteilten Singleton-Stream. Jedes **Modul erzeugt seine eigene Instanz**
mit **eigenem API-Key und eigenem Filter**.
**Begründung:** Blockchain-/WSS-Streams werden modulspezifisch **gefiltert** (sonst viel zu
umfangreich). Ein einzelner, Core-gesteuerter Stream, auf den mehrere Module gleichzeitig
zugreifen, wäre für jedes einzelne Modul mit nutzlosen Informationen geflutet.
**Aufteilung des heutigen `AlchemyWebsocketService`:**
- **Core** (`PolyTrader.Core.Streaming`): Verbindungs-Mechanik — `ClientWebSocket`, `eth_subscribe`,
Empfangs-Loop, Decode, Reconnect/429-Backoff, Health. Parametrisiert über eine
`BlockchainWssSubscription` (Contract, Topics, Adress-Filter) + RPC-URL/Key. Als **Factory**
(`IBlockchainWssClientFactory.Create()`), damit jedes Modul eine eigene Instanz bekommt.
- **Modul** (`CopyTrading`): `CopyTradingBlockchainListener : BackgroundService`, der eine
Core-WSS-Instanz mit dem Copytrading-Filter (Wallets der getrackten Master-Trader) + dem
Modul-eigenen Alchemy-Key betreibt, den gefilterten Substream konsumiert und selbst reagiert
(TraderMonitor-Poll, Re-Subscribe bei Trader-Listen-Änderung).
Analog für den Polymarket-User/Market-WSS (`PolymarketWssClient` → Core-Verbindungsklasse +
Modul-Listener). `IsAlchemyHealthy` (heute im Core-State) wird zum Health-Signal der jeweiligen
Modul-Instanz.
---
## 3. Persistenz-Strategie
- **Zielrichtung: Wechsel auf MySQL** via **EF Core + Pomelo.EntityFrameworkCore.MySql**,
gekapselt hinter Repository-Interfaces im Core.
- **Begründung:** DB liegt off-hot-path (Live-Pfad ist RAM-only) → kein Performance-Nachteil.
Gewinn: saubere relationale Tabellen statt Collection-per-Account + Shim, ACID,
EF-Migrations, Standard-Backups.
- **Risikoarm durch Reihenfolge:** Zuerst Repository-Abstraktion einziehen (Phase 3),
MySQL-Umstieg als eigene späte Phase (Phase 6). Die Modularisierung ist davon
entkoppelt und nicht blockiert.
- **Aufräumen:** LiteDB-Paket, `data.db` und `MongoDbLiteDBShim` entfallen nach der Migration.
- **ORM: Entity Framework Core** (entschieden) — Migrations + wenig Boilerplate.
---
## 4. Phasenplan
> Jede Phase endet mit grünem Debug-Build + lauffähiger App + Git-Commit.
### Phase 0 — Fundament: Versionskontrolle & Aufräumen *(ABGESCHLOSSEN 2026-07-01)*
- [x] `git init` (Branch `main`), `.gitignore` (bin/, obj/, .vs/, *.user, *.db, server_settings.xml, agentspace/antigravity/, .claude/settings.local.json).
- [x] Alle 11 `.bak*`-Dateien entfernt (per `-f` im Baseline-Commit `475d396` archiviert, danach entfernt → rekonstruierbar).
- [x] Tote Stubs entfernt: `services/database.cs`, `services/settings.cs`, `polymarket/*.cs`.
- [x] Threema-Lib unter `libs/` vendored (nested `.git` entfernt).
- [x] Baseline-Commit `475d396` + Cleanup-Commit `f76ad73`; Debug-Build 0 Fehler verifiziert.
### Phase 1 — Multi-Projekt-Gerüst anlegen *(ABGESCHLOSSEN 2026-07-01, Commit `4f130ff`)*
- [x] Drei Projekte: `PolyTrader.App` (umbenanntes WinForms-Projekt, Root),
`src/PolyTrader.Core`, `src/PolyTrader.Modules.CopyTrading` (net8.0-windows).
- [x] Referenzen: App → Core + CopyTrading; CopyTrading → Core; Core → nichts.
- [x] App-csproj: `src\**` vom Globbing ausgeschlossen (keine Glob-Kollision);
RootNamespace auf `PolyTraderSharp` gepinnt (schützt .resx/Namespaces).
- [x] Threema-Lib-Referenz bleibt im App-Projekt (wandert in Phase 4 zu Bedarf in Core).
- [x] **Ergebnis:** Solution-Build 0 Fehler, Code liegt weiterhin im App-Projekt.
- [ ] *Offen für spätere Phasen:* NuGet-Pakete beim Code-Umzug auf Core/Modul verteilen.
### Phase 2 — Konfiguration externalisieren *(ABGESCHLOSSEN 2026-07-01, Commit `e312fbb`)*
- [x] `appsettings.json` eingeführt (Mongo-Connection + DB-Name), Copy-to-Output.
- [x] `DatabaseOptions` im Core, via `IOptions<T>` gebunden; hart codierte Strings
aus `Program.cs` entfernt.
- [x] Startup-Cleanup-Hack aus `Main()` entfernt und gekapselt nach Host-Build über
die konfigurierte DB neu verankert.
- [ ] *Offen (bewusst später):* Alchemy-Key / Mullvad-Account / Threema bleiben vorerst
im GUI-editierbaren `server_settings.xml` (kein Konflikt mit Settings-Tab).
### Phase 3 — Persistenz-Abstraktion (DB noch Mongo) *(IN ARBEIT)*
- [x] **3a** (`8b3264f`): Core-Modelle `AccountState`/`Position`/`MarketData` in den Core
verschoben (Namespace `PolyTraderSharp.Models` beibehalten), MongoDB.Driver-Paket im Core.
- [x] **3b** (`ed5d6e3`): Repository-Interfaces + Mongo-Implementierungen im Core
(`IAccountRepository`, `IMarketRepository`, `IPositionRepository`), `AddCorePersistence()`.
- [x] **3c** (`7197f9b`): Unkritische Call-Sites migriert (MarketSyncService, PolymarketWssClient).
- [x] **3d — Hot-Path** (`a0e367e`, `0c6fc6a`): TraderMonitorService + CopyTradingEngine
auf `IPositionRepository`/`IMarketRepository`/`IAccountRepository` umgestellt.
`_db` aus CopyTradingEngine komplett entfernt; Verhalten unverändert.
- [ ] **frm_main-UI:** Account/Market/Demo-Position-Zugriffe → wird zusammen mit der
UI-Zerlegung in Phase 5 migriert (vermeidet Wegwerf-Arbeit).
- [ ] *Offen für Phase 5:* generisches `ITradeLogRepository` (Core) + `ICopyTradeLogRepository`
+ `ITraderRepository` (Modul), sobald `ClosedTrade`/`TrackedTrader` ins Modul wandern.
- [ ] **Ergebnis (Ziel):** Kein direkter DB-Zugriff mehr außerhalb der Repository-Schicht.
### Phase 4 — Core herauslösen *(IN ARBEIT)*
- [x] **4.1** (`9039af8`): TerminalLogger, JobManager, JobStatusRow → Core;
toten Stub `logging.cs` gelöscht.
- [x] **4.2** (`eebe992`): PolymarketClobClient → Core (+ Nethereum.Web3), reines Verschieben.
- [x] **4.3** (`8c126cd`): ServerSettings → Core.
- [x] **4.4** (`a1ce3fc`): `IPolyTraderModule`-Contract im Core (UI-Teil auf Phase 5 vertagt).
- [x] **4.5** (`c88eac5`): Startup-Reihenfolge-Fix — `StartupHydrationService` (IHostedService,
als erster registriert) hydriert Accounts/Trader vor den Trading-Services;
`frm_main.LoadDatabaseAndState` entfernt.
- [x] **4.6a** (`9c068b4`): CopySignal + PolymarketApiService → Core.
- [x] **4.7** (`0ffc041`): MullvadVpnService + ThreemaService (+ Threema-Lib-Ref) → Core;
toter Stub `mullvad.cs` gelöscht.
- [ ] **BLOCKIERT durch TradingState-Split (→ Phase 5):** MarketSyncService,
AlchemyWebsocketService, PolymarketWssClient, SnapshotService nutzen `TradingState`
(MarketCache/Accounts/globale Flags). Sie können erst nach dem Split in den Core.
- [x] **Ergebnis:** Core baut eigenständig und enthält jetzt: Modelle (Account/Position/
Market/CopySignal/JobStatusRow/ServerSettings), Repository-Schicht, Config, Logging,
JobManager, CLOB-Client, API-Service, Mullvad, Threema, IPolyTraderModule.
**Stand nach Phase 4:** Der Core ist substanziell und eigenständig. Was noch in der App liegt:
Modul-Services (TraderMonitor, CopyTradingEngine, Analytics-Jobs), die TradingState-abhängige
Infra (MarketSync, Alchemy, WSS, Snapshot), PersistenceService, StartupHydrationService,
der Shim, `TradingState`, `frm_main` und die Modul-Modelle (TrackedTrader, TraderAnalyticsResult,
MasterTraderHistoryRecord, ClosedTrade, DashboardRow). Der **TradingState-Split** ist der
Dreh- und Angelpunkt für Phase 5.
> **Entscheidung (2026-07-01):** `CopySignal` wird ein **Core**-Typ (generisches Markt-Trade-
> Signal). Das entkoppelt die Polymarket-Infrastruktur sauber in den Core. Der Channel/Workflow
> bleibt Copytrading. Umbenennung zu `TradeSignal` optional/später.
### Phase 5 — CopyTrading-Modul herauslösen *(IN ARBEIT)*
- [x] **5.1** (`55050a1`): Modul-Modelle (TrackedTrader, TraderAnalyticsResult,
MasterTraderHistoryRecord) ins Modul verschoben.
- [x] **5.2** (`f8d395b`): **TradingState-Split** — Core `TradingState` (globale Schalter,
Accounts, MarketCache, GlobalPnl) vs. `CopyTradingState` im Modul (Traders,
MasterTraderPositions, TraderAnalyticsCache, TotalCopyTrades, PendingOrderTimestamps,
SixSharesMinimum); 10 Konsumenten umgestellt. Modulgrenze auf State-Ebene gezogen.
- [x] **5.3a** (`f5e7eaf`): MarketSyncService → Core (nur Core-State).
- [x] **5.3-WSS 1/2** (`3be75c0`): Core-WSS-Verbindungsklasse extrahiert
(`IBlockchainWssClient` + Factory + Modelle in `PolyTrader.Core.Streaming`);
`AlchemyWebsocketService` nutzt sie via Factory. Verhaltensneutral.
- [x] **ClosedTrade-Migration** (`88fc982`): `ClosedTrade` → Modul, `ICopyTradeLogRepository`
(+ Mongo-Impl) im Modul; `closed_trades`-Zugriffe der Services (TraderMonitor,
Persistence, WSS, TraderAnalytics) auf das Repo umgestellt. TraderMonitor nutzt kein
`_db` mehr. frm_main/Program.cs bleiben auf `_db`.
- [ ] **5.3b (jetzt unblockiert):** Modul-Services physisch ins Modul-Projekt verschieben:
TraderMonitorService, CopyTradingEngine, TraderAnalyticsJob, MasterTraderAnalyticsJob.
(Vorher: reststehende `PolyTraderSharp.Extensions`-Usings in CopyTradingEngine entfernen.)
- [ ] **5.3-WSS 2/2:** `CopyTradingBlockchainListener` → Modul (eigener Key + Filter);
API-Keys → Modul-Settings. Analog `PolymarketWssClient`.
- **UI-Trennung (Launcher-Modell, entschieden 2026-07-01):** Hauptfenster = schlanke
Startleiste; jede Ansicht öffnet als eigenständiges Fenster. Module liefern designbare
`UserControl`s via `IPolyTraderModule.RegisterUi` / `IModuleUiHost`. `frm_main` bleibt
übergangsweise als „Legacy-UI" per Button erreichbar, bis alle Views extrahiert sind.
- [x] UI-Contract im Core (`IModuleUiHost`, `ModuleView`, `RegisterUi`) — `26dd68a`.
- [x] Proof-of-Pattern: `LauncherForm` + `ViewHostForm` + `ShellUiHost` + erste View
`TerminalView` (designbar); App startet Launcher — `3503bbb`.
- [ ] Restliche Views view-für-view extrahieren:
**App/Core:** Jobs, Server Settings, Dashboard (Overview), License, Accounts (Slave),
Offene Positionen. **Modul:** Master-Traders, Top/Flop-Analytics, Geschlossene Trades.
- [ ] `frm_main` (Legacy) entfernen, sobald alle Views raus sind.
- [ ] `CopyTradingModule : IPolyTraderModule` implementieren (Services + UI-Tabs +
Settings-Sektion + Modul-Log + Start/Stop).
- [ ] Dualen Trade-Log verdrahten: beim Schließen kopierter Trades in Core-Log **und**
Copytrading-Log schreiben.
- [ ] Latenten Collection-Namensbug beheben (`traders` vs. `trackers`).
- [ ] **Ergebnis:** Copytrading ist ein eigenständiges, entfernbares Modul.
### Phase 6 — MySQL-Migration
- [ ] EF Core + Pomelo einrichten; relationales Schema modellieren
(u.a. `positions` mit `account_id` statt Collection-per-Account;
`trader_accounts` Join-Tabelle für `AssignedAccountIds`).
- [ ] Zweite Repository-Implementierung (MySQL) hinter den bestehenden Interfaces.
- [ ] Einmaliges Migrationsskript Mongo → MySQL (agentspace/scripts).
- [ ] Umschalten per Konfiguration; Mongo/LiteDB/Shim + `data.db` entfernen.
### Phase 7 — Nacharbeiten *(optional, später zu priorisieren)*
- [ ] Test-Projekt: Risk-/Entscheidungslogik als reine Funktionen extrahieren & testen.
- [ ] God-Methoden splitten (`PollLiveAccountsAsync`, `ProcessAccountOrderAsync`);
duplizierte Closed-Trade-Erzeugung zentralisieren.
- [ ] Leere `catch {}` durch gezieltes Logging ersetzen.
- [ ] Secrets-Verschlüsselung (DPAPI) für PrivateKey/ApiSecret/ApiPassphrase.
- [ ] TerminalLogger auf `Microsoft.Extensions.Logging` + UI-Sink umstellen.
---
## 5. Datei-→-Ziel-Zuordnung (Referenz)
| Aktuell | Ziel |
|---------|------|
| `Program.cs` | PolyTrader.App |
| `frm_main.*` | PolyTrader.App (Shell) + Copytrading-Tabs → Modul |
| `frm_analytics.*` | PolyTrader.Modules.CopyTrading |
| `TradingState.cs` | aufgeteilt: Core + Modul |
| `services/PolymarketApiService.cs` | Core |
| `services/PolymarketClobClient.cs` | Core |
| `services/PolymarketWssClient.cs` | Core |
| `services/AlchemyWebsocketService.cs` | Core |
| `services/MullvadVpnService.cs`, `mullvad.cs` | Core |
| `services/ThreemaService.cs` | Core |
| `services/JobManager.cs`, `TerminalLogger.cs`, `logging.cs` | Core |
| `services/PersistenceService.cs` | Core (generischer Trade-Log-Writer); Copytrading-Detail-Writer → Modul |
| `services/MarketSyncService.cs`, `SnapshotService.cs` | Core |
| `Extensions/MongoDbLiteDBShim.cs` | Core (temporär), entfällt in Phase 6 |
| `services/CopyTradingEngine.cs` | Modul |
| `services/TraderMonitorService.cs` | Modul |
| `services/MasterTraderAnalyticsJob.cs`, `TraderAnalyticsJob.cs` | Modul |
| `Models/AccountState.cs`, `Position.cs`, `MarketData.cs`, `ServerSettings.cs`, `JobStatusRow.cs`, `DashboardRow.cs` | Core |
| `Models/ClosedTrade.cs` | aufgeteilt: generischer `TradeRecord` → Core, `CopyTradeRecord` (mit SourceTrader-Feldern) → Modul |
| `Models/TrackedTrader.cs`, `CopySignal.cs`, `TraderAnalyticsResult.cs`, `MasterTraderHistoryRecord.cs` | Modul |
| `services/database.cs`, `settings.cs`, `polymarket/*.cs` | löschen (Phase 0) |
| `*.bak*` | löschen (Phase 0) |
---
## 6. Getroffene Entscheidungen (2026-07-01)
1. **Eigene Trading-Accounts → Core**, **kopierte Master-Trader → Copytrading-Modul.**
2. **Zweistufiges Trade-Logging:** generischer Core-Log (modulübergreifend) **und**
zusätzlicher Copytrading-Detail-Log im Modul (siehe 2.4).
3. **ORM: Entity Framework Core.**
4. **Dashboard:** Core liefert Gesamt-Overview über alle Module; Module liefern
eigene Detail-Analysen (siehe 2.5).
5. **Settings:** getrennte Core- und Modul-Settings-Sektionen (siehe 2.6).
---
## 7. Risiken & Gegenmaßnahmen
- **CLOB-Regression:** Höchstes Risiko. Gegenmaßnahme: CLOB-Client möglichst unverändert
in den Core verschieben (nur Namespace/Referenzen), keine Logikänderung in der
Umstrukturierungsphase.
- **Startup-Race weiterhin aktiv, bis Phase 4:** Bis der Startup-Fix greift, bleibt das
bestehende Verhalten kein neues Risiko, aber früh angehen.
- **Datenmigration (Phase 6):** Server läuft produktiv. Migration mit Read-Only-Export +
Verifikation vor Umschaltung; Rollback-Pfad (Mongo bleibt bis Verifikation bestehen).
@@ -0,0 +1,98 @@
# Umsetzungsplan: Strategie-Drift-Erkennung für Master-Trader (B-S2)
> Stand: 2026-07-11
> Ziel: Verhaltens-Änderungen eines Masters erkennen, BEVOR sie sich im Copy-PnL
> niederschlagen. Die bestehende Auto-Pause (Copy-PnL-basiert) ist ein nachlaufender
> Indikator — bei 95-¢-Tradern sieht man den Schaden erst nach mehreren Verlusten.
> Verhalten läuft dem PnL voraus: Ein Wetter-Bot, der plötzlich Politik-Longshots
> kauft, hat die Strategie gewechselt, lange bevor die Verluste messbar sind.
> Modul: PolyTrader.Modules.CopyTrading (baut auf vorhandenem MasterTraderAnalyticsJob auf).
---
## 1. Der Verhaltens-Fingerprint
Je Master werden zwei Fenster verglichen: **Referenz** (30 Tage bzw. die von
Predictalytics gelieferte Baseline) vs. **aktuell** (7 Tage). Datenquelle: die
Activity-/History-Daten, die der `MasterTraderAnalyticsJob` bereits lädt
(`mod_copytrading_mt_history` + Data-API-Activity; für Preisband/Größe die
Activity-Items — Felder existieren in den bereits geparsten JSONs).
Fingerprint-Metriken (pure Klasse `Logic/TraderFingerprint.cs`, voll unit-getestet):
| Metrik | Definition | Drift-Beispiel |
|---|---|---|
| `TradesPerWeek` | Trade-Frequenz | Bot-Betreiber wechselt von 40 auf 400/Woche |
| `CategoryMix` | Einsatz-Anteil je Kategorie (Vektor) | Wetter-Bot kauft plötzlich Politik |
| `PriceBandMix` | Einsatz-Anteil je Einstiegs-Preisband (10-¢-Bänder) | Favoriten-Halter kauft Longshots |
| `MedianHoldHours` | Median Haltedauer (Kauf→Close/Resolution) | Halter wird Day-Trader |
| `SellRatio` | Anteil aktiv verkaufter Positionen | „Stur-Halter" beginnt zu verkaufen |
| `SizeP90Rel` | 90. Perzentil Positionsgröße relativ zur Referenz | Martingale-/Tilt-Muster |
### Drift-Score
Pro Metrik eine normierte Abweichung (für Anteils-Vektoren: L1-Distanz / 2 → 0..1;
für Skalare: `|akt ref| / max(ref, ε)` gekappt auf 1). Gesamt:
```
DriftScore = gewichtete Summe (Default-Gewichte: CategoryMix 0.3, PriceBandMix 0.25,
SellRatio 0.2, TradesPerWeek 0.1, MedianHoldHours 0.1, SizeP90Rel 0.05)
```
Schwellen (global in `CopyTradingState`, per PropertyGrid änderbar, mit
[Description]): `DriftWarnScore` (Default 0.25) und `DriftPauseScore` (Default 0.5).
**Mindeststichprobe:** unter 10 Trades im 7-Tage-Fenster keine Bewertung (Rauschen).
## 2. Aktionen bei Drift
| Stufe | Bedingung | Aktion |
|---|---|---|
| Beobachten | Score < Warn | nichts; Score in UI-Spalte sichtbar |
| **Warnen** | Warn ≤ Score < Pause | Threema-Meldung mit den 2 größten Abweichungen („Kategorie-Mix: Wetter 90→40 %, Politik 0→45 %"); Master in UI gelb |
| **Neu-Trades pausieren** | Score ≥ Pause UND `AutoPauseEnabled` | NEUE BUYs dieses Masters aussetzen (`DriftPaused`-Flag auf TrackedTrader, Engine-Check im BUY-Pfad analog ExitPending); offene Positionen + SELL-Handling laufen normal weiter; Threema; Reaktivierung manuell |
Bewusst: Drift pausiert nur **Neu-Käufe** — es verkauft nichts. Bestehende
Positionen sind Sache der normalen Exit-Mechanik (Halter: Resolution).
## 3. Umsetzung
### Slice D-1: Pure Logik + Persistenz
- `Logic/TraderFingerprint.cs`: `Compute(IEnumerable<TradeObservation>)`
Fingerprint; `Drift(reference, current)` → Score + Top-Abweichungen. Unit-Tests
(Vektor-Distanzen, Mindeststichprobe, Rand: leere Referenz).
- `TrackedTrader`: Felder `FingerprintBaselineJson` (Referenz, von Predictalytics
importierbar ODER selbst aus 30 Tagen berechnet), `DriftScore`, `DriftPaused`,
`DriftDetail` (Kurztext) + Migration.
- `MasterTraderHistoryRecord` erweitern um die dafür nötigen Felder (EntryPrice-Band,
Kategorie, Size, Haltedauer), sofern noch nicht vorhanden — beim History-Download
mit befüllen (Daten sind in den API-Antworten enthalten).
### Slice D-2: Job-Integration
- Im `MasterTraderAnalyticsJob` nach dem History-Download: Fingerprint aktuell (7 T)
vs. Referenz (30 T bzw. BaselineJson) → Score, Aktionen gemäß Tabelle.
- **Frequenz:** Der Job läuft 12-stündlich — für Drift zu träge. Leichten
Stunden-Tick ergänzen (nur Fingerprint-Neuberechnung aus bereits geladenen
History-Daten, KEINE zusätzlichen API-Calls; die 12-h-Läufe aktualisieren die
Rohdaten).
- Referenz-Handhabung: Baseline wird NICHT automatisch nachgezogen, solange eine
Warnung/Pause aktiv ist (sonst „lernt" die Referenz die Drift). Nach manueller
Entwarnung: Baseline auf aktuelles 30-T-Fenster zurücksetzen (Button in UI).
### Slice D-3: Engine + UI
- Engine-BUY-Pfad: `DriftPaused`-Check (analog `IsActive`), TradeReasoning-Log.
- `MastersTradersView`: Spalten DriftScore (mit Ampelfarbe) + DriftDetail;
Kontextmenü „Drift entwarnen + Baseline zurücksetzen".
## 4. Akzeptanzkriterien
1. Unit-Tests: konstruierte Drift-Szenarien (Kategorie-Wechsel, Frequenz-Explosion,
Longshot-Umstieg) erzeugen erwartete Scores; stabile Master bleiben < Warn.
2. Simulierter Kategorie-Wechsel in Testdaten führt zu `DriftPaused` + Engine
verweigert Neu-BUY mit nachvollziehbarem Log.
3. Kein zusätzlicher Data-API-Traffic durch den Stunden-Tick (nur DB/RAM).
4. Threema-Meldungen enthalten die konkreten Top-Abweichungen, nicht nur den Score.
## 5. Abgrenzung
- Ersetzt NICHT die PnL-Auto-Pause (Phase 3.3, bleibt) — Drift ist das Frühwarnsystem,
PnL-Pause das Sicherheitsnetz.
- Sniper-Metriken (Plan Phase 3.2, Median-Haltezeit via Activity-Pagination) sind ein
Spezialfall dieses Fingerprints — bei Umsetzung zusammenlegen statt doppelt bauen.