Baseline: Ausgangszustand vor Modularisierung

Erster Commit des bestehenden monolithischen WinForms-Copytraders,
inklusive der Alt-Backups (*.bak), damit diese dauerhaft in der
Historie rekonstruierbar bleiben. Threema-Lib unter libs/ wurde
vendored (nested .git entfernt).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
bergm
2026-07-01 13:16:16 +02:00
co-authored by Claude Opus 4.8
commit 475d396f80
147 changed files with 25455 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
using System;
using MongoDB.Driver;
using PolyTraderSharp.Extensions;
using System.ComponentModel;
using System.Collections.Concurrent;
using System.Linq;
namespace PolyTraderSharp.Models
{
public class AccountState
{
[Browsable(false)]
[MongoDB.Bson.Serialization.Attributes.BsonId] public int AccountId { get; set; }
[Category("01. General")]
public string Name { get; set; } = string.Empty;
[Category("02. Wallet & Keys")]
public string WalletAddress { get; set; } = string.Empty;
[Category("02. Wallet & Keys")]
public string ApiKey { get; set; } = string.Empty;
[Category("02. Wallet & Keys")]
public string ApiSecret { get; set; } = string.Empty;
[Category("02. Wallet & Keys")]
public string ApiPassphrase { get; set; } = string.Empty;
[Category("02. Wallet & Keys")]
public string PrivateKey { get; set; } = string.Empty;
[Category("01. General")]
public bool IsDemo { get; set; }
[Category("01. General")]
public bool IsActive { get; set; } = true;
[Category("01. General")]
public bool CloseOnlyMode { get; set; } = false;
[Category("03. Payouts")]
public string PayoutAddress { get; set; } = string.Empty;
[Category("03. Payouts")]
public decimal PayoutLimitUsd { get; set; } = 0;
// Balances
[Browsable(false)]
public decimal TotalBalance { get; set; }
[Browsable(false)]
public decimal AvailableBalance { get; set; }
// Risk Settings
[Category("04. Risk Management")]
public decimal PerMarketLimit { get; set; } = 5.0m;
[Category("04. Risk Management")]
public decimal MaxPriceDifference { get; set; } = 2.0m;
[Category("04. Risk Management")]
public decimal MaxBuyPrice { get; set; } = 0.98m;
[Category("04. Risk Management")]
public decimal ProfitTarget { get; set; } = 50.0m;
[Category("04. Risk Management")]
public decimal PreRedeemLimit { get; set; } = 0.0m;
[Category("04. Risk Management")]
public decimal PerMasterLimit { get; set; } = 10.0m;
// Time limits
[Category("05. Time Limits")]
public decimal perMaxTime6h { get; set; } = 20.0m;
[Category("05. Time Limits")]
public decimal perMaxTime24h { get; set; } = 20.0m;
[Category("05. Time Limits")]
public decimal perMaxTime72h { get; set; } = 20.0m;
[Category("05. Time Limits")]
public decimal perMaxTimeNone { get; set; } = 40.0m;
[Browsable(false)]
public ConcurrentDictionary<string, Position> OpenPositions { get; } = new(StringComparer.OrdinalIgnoreCase);
[Browsable(false)]
public bool HasOpenLimitOrders { get; set; } = false;
public void UpdateBalance(decimal available)
{
AvailableBalance = available;
decimal inPositions = OpenPositions.Values.Sum(p => (decimal)p.AmountUsd);
TotalBalance = AvailableBalance + inPositions;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
namespace PolyTraderSharp.Models
{
public class ClosedTrade
{
[MongoDB.Bson.Serialization.Attributes.BsonId] public int TradeId { get; set; }
public int AccountId { get; set; }
public int SourceTraderId { get; set; }
public bool IsDemo { get; set; }
public string TokenId { get; set; } = string.Empty;
public string MarketSlug { get; set; } = string.Empty;
public string MarketQuestion { get; set; } = string.Empty;
public string Outcome { get; set; } = string.Empty;
public string Side { get; set; } = string.Empty;
public decimal EntryPrice { get; set; }
public decimal ExitPrice { get; set; }
public decimal Size { get; set; }
public decimal RealizedPnl { get; set; }
public decimal PnlPercent { get; set; }
public decimal TotalFees { get; set; }
public DateTime OpenedAt { get; set; }
public DateTime ClosedAt { get; set; }
public string ExitReason { get; set; } = string.Empty;
}
public class ClosedTradeRow : ClosedTrade
{
public string AccountName { get; set; } = string.Empty;
public string SourceTraderName { get; set; } = string.Empty;
[System.ComponentModel.Browsable(false)]
public string SourceTraderAddress { get; set; } = string.Empty;
}
}
+32
View File
@@ -0,0 +1,32 @@
namespace PolyTraderSharp.Models
{
public class ClosedTrade
{
public int TradeId { get; set; }
public int AccountId { get; set; }
public int SourceTraderId { get; set; }
public bool IsDemo { get; set; }
public string TokenId { get; set; } = string.Empty;
public string MarketSlug { get; set; } = string.Empty;
public string MarketQuestion { get; set; } = string.Empty;
public string Outcome { get; set; } = string.Empty;
public string Side { get; set; } = string.Empty;
public decimal EntryPrice { get; set; }
public decimal ExitPrice { get; set; }
public decimal Size { get; set; }
public decimal RealizedPnl { get; set; }
public decimal PnlPercent { get; set; }
public decimal TotalFees { get; set; }
public DateTime OpenedAt { get; set; }
public DateTime ClosedAt { get; set; }
public string ExitReason { get; set; } = string.Empty;
}
public class ClosedTradeRow : ClosedTrade
{
public string AccountName { get; set; } = string.Empty;
}
}
+19
View File
@@ -0,0 +1,19 @@
namespace PolyTraderSharp.Models
{
public class CopySignal
{
public int SourceTradeId { get; set; }
public int TraderId { get; set; }
public string MarketSlug { get; set; } = string.Empty;
public string ConditionId { get; set; } = string.Empty;
public string TokenId { get; set; } = string.Empty;
public string MarketQuestion { get; set; } = string.Empty;
public string Side { get; set; } = "BUY";
public decimal Price { get; set; }
public decimal Size { get; set; }
public string Outcome { get; set; } = string.Empty;
public DateTime Timestamp { get; set; }
public DateTime? EndDate { get; set; }
public string Reason { get; set; } = string.Empty;
}
}
+50
View File
@@ -0,0 +1,50 @@
using System.ComponentModel;
using System.Drawing;
namespace PolyTraderSharp.Models
{
public class DashboardRow
{
[Browsable(false)]
public int AccountId { get; set; }
[Browsable(false)]
public bool IsDemo { get; set; }
[Browsable(false)]
public bool IsActive { get; set; }
[DisplayName("Account")]
public string AccountName { get; set; } = string.Empty;
[DisplayName("Balance Gesamt")]
public decimal TotalBalance { get; set; }
[DisplayName("Balance verfügbar")]
public decimal AvailableBalance { get; set; }
[DisplayName("Balance in Positionen")]
public decimal PositionBalance { get; set; }
[DisplayName("Offene Trades")]
public int OpenTradesCount { get; set; }
[DisplayName("Trades (24h)")]
public int ClosedTrades24h { get; set; }
[DisplayName("P&L (24h)")]
public decimal Pnl24h { get; set; }
[DisplayName("Winrate (24h)")]
public string Winrate24h { get; set; } = "0%";
[DisplayName("Trades (7d)")]
public int ClosedTrades7d { get; set; }
[DisplayName("P&L (7d)")]
public decimal Pnl7d { get; set; }
[DisplayName("Winrate (7d)")]
public string Winrate7d { get; set; } = "0%";
}
}
+30
View File
@@ -0,0 +1,30 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace PolyTraderSharp.Models
{
public class JobStatusRow : INotifyPropertyChanged
{
private string _jobName = "";
private string _description = "";
private bool _isEnabled = true;
private DateTime? _lastRun;
private DateTime? _nextRun;
private string _statusText = "Initializing...";
public string JobName { get => _jobName; set { _jobName = value; OnPropertyChanged(); } }
public string Description { get => _description; set { _description = value; OnPropertyChanged(); } }
public bool IsEnabled { get => _isEnabled; set { _isEnabled = value; OnPropertyChanged(); } }
public DateTime? LastRun { get => _lastRun; set { _lastRun = value; OnPropertyChanged(); } }
public DateTime? NextRun { get => _nextRun; set { _nextRun = value; OnPropertyChanged(); } }
public string StatusText { get => _statusText; set { _statusText = value; OnPropertyChanged(); } }
public Func<Task>? ManualTriggerAction { get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
+21
View File
@@ -0,0 +1,21 @@
namespace PolyTraderSharp.Models
{
public class MarketData
{
[MongoDB.Bson.Serialization.Attributes.BsonId] public string Id { get; set; } = string.Empty;
public string ConditionId { get; set; } = string.Empty;
public string Question { get; set; } = string.Empty;
public string Slug { get; set; } = string.Empty;
public DateTime? EndDate { get; set; }
public bool Active { get; set; }
public bool Closed { get; set; }
public string Category { get; set; } = string.Empty;
// Will store the JSON array string of token IDs, e.g. "[\"123\", \"456\"]"
public string ClobTokenIds { get; set; } = string.Empty;
public string Outcomes { get; set; } = string.Empty; // e.g. "[\"Yes\", \"No\"]"
public bool NegRisk { get; set; }
}
}
+23
View File
@@ -0,0 +1,23 @@
using System;
using MongoDB.Driver;
using PolyTraderSharp.Extensions;
namespace PolyTraderSharp.Models
{
public class MasterTraderHistoryRecord
{
[MongoDB.Bson.Serialization.Attributes.BsonId] public string Id { get; set; } = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
// Verknüpfung zum Master Trader
public int TraderId { get; set; }
// Verknüpfung zum Markt
public string TokenId { get; set; } = string.Empty;
// Der erfasste Profit / Loss auf Polymarket
public decimal RealizedPnl { get; set; }
// Timestamp des Trades
public DateTime ClosedAt { get; set; }
}
}
+23
View File
@@ -0,0 +1,23 @@
namespace PolyTraderSharp.Models
{
public class Position
{
[MongoDB.Bson.Serialization.Attributes.BsonId]
public string TokenId { get; set; } = string.Empty;
public string MarketSlug { get; set; } = string.Empty;
public string ConditionId { get; set; } = string.Empty;
public int SourceTraderId { get; set; }
public string SourceTraderName { get; set; } = string.Empty;
public string SourceTraderAddress { get; set; } = string.Empty;
public string MarketQuestion { get; set; } = string.Empty;
public string Outcome { get; set; } = string.Empty;
public string Side { get; set; } = "BUY";
public decimal EntryPrice { get; set; }
public decimal Size { get; set; } // Shares
public decimal AmountUsd { get; set; }
public decimal CurrentPrice { get; set; }
public decimal CurrentValueUsd { get; set; }
public System.DateTime? ExpiryDate { get; set; }
public System.DateTime OpenedAt { get; set; } = System.DateTime.UtcNow;
}
}
+106
View File
@@ -0,0 +1,106 @@
using System.ComponentModel;
using System.IO;
using System.Xml.Serialization;
namespace PolyTraderSharp.Models
{
public class ServerSettings
{
[Category("Threema Notifications")]
[DisplayName("Threema Enabled")]
[Description("Enable or disable Threema notifications.")]
public bool ThreemaEnabled { get; set; } = true;
[Category("Threema Notifications")]
[DisplayName("Gateway ID")]
[Description("The Threema Gateway ID (e.g. *3MAGW01).")]
public string ThreemaGatewayId { get; set; } = "*3MAGW01";
[Category("Threema Notifications")]
[DisplayName("Gateway Secret")]
[Description("The secret for the Threema Gateway integration.")]
public string ThreemaSecret { get; set; } = "";
[Category("Threema Notifications")]
[DisplayName("Private Key")]
[Description("The Private Key (hex) for End-to-End encryption.")]
public string ThreemaPrivateKey { get; set; } = "";
[Category("Threema Notifications")]
[DisplayName("Group ID")]
[Description("The Threema Group ID to send messages to.")]
public string ThreemaGroupId { get; set; } = "";
[Category("Threema Notifications")]
[DisplayName("Webhook Port")]
[Description("The local port to listen on for incoming Threema messages (e.g. 8080).")]
public int ThreemaWebhookPort { get; set; } = 8080;
[Category("Threema Notifications")]
[DisplayName("Report Interval (Hours)")]
[Description("Interval for the automatic summary report.")]
public int ThreemaReportIntervalHours { get; set; } = 6;
[Category("Mullvad VPN")]
[DisplayName("VPN Enabled")]
[Description("Enable or disable automatic VPN rotation.")]
public bool VpnEnabled { get; set; } = false;
[Category("Mullvad VPN")]
[DisplayName("Mullvad Account")]
[Description("Account ID for Mullvad VPN.")]
public string MullvadAccount { get; set; } = "7748925650632296";
[Category("Mullvad VPN")]
[DisplayName("VPN Location")]
[Description("Target VPN location (e.g. cz).")]
public string VpnLocation { get; set; } = "cz";
[Category("Mullvad VPN")]
[DisplayName("Mullvad CLI Path")]
[Description("Path to mullvad.exe")]
public string MullvadCliPath { get; set; } = @"C:\Program Files\Mullvad VPN\resources\mullvad.exe";
[Category("Blockchain Listener")]
[DisplayName("Enable Blockchain Listener")]
[Description("If true, connects to Alchemy WSS for faster on-chain signal detection.")]
public bool EnableBlockchainListener { get; set; } = true;
[Category("Blockchain Listener")]
[DisplayName("Polygon RPC URL")]
[Description("RPC URL for Alchemy WSS.")]
public string PolygonRpcUrl { get; set; } = "wss://polygon-mainnet.g.alchemy.com/v2/iWCbs9p3nf-8OpR-BtvGi";
[Category("Polymarket WebSockets")]
[DisplayName("Use Polymarket WebSockets")]
[Description("If true, connects to Polymarket WSS for live market prices and user events.")]
public bool UsePolymarketWebsockets { get; set; } = false;
public static ServerSettings Load(string path)
{
if (!File.Exists(path))
return new ServerSettings();
try
{
var serializer = new XmlSerializer(typeof(ServerSettings));
using var fs = new FileStream(path, FileMode.Open);
return (ServerSettings?)serializer.Deserialize(fs) ?? new ServerSettings();
}
catch
{
return new ServerSettings();
}
}
public void Save(string path)
{
var serializer = new XmlSerializer(typeof(ServerSettings));
using var fs = new FileStream(path, FileMode.Create);
serializer.Serialize(fs, this);
}
}
}
+55
View File
@@ -0,0 +1,55 @@
using System;
using MongoDB.Driver;
using PolyTraderSharp.Extensions;
using System.ComponentModel;
using System.Collections.Generic;
namespace PolyTraderSharp.Models
{
public class TrackedTrader
{
[Browsable(false)]
[MongoDB.Bson.Serialization.Attributes.BsonId] public int Id { get; set; }
[Category("01. Identification")]
public string WalletAddress { get; set; } = string.Empty;
[Category("01. Identification")]
public string DisplayName { get; set; } = string.Empty;
[Category("02. Categorization")]
public string Category { get; set; } = "NEW_BIG_BET";
[Category("02. Categorization")]
public string Description { get; set; } = string.Empty;
[Category("02. Categorization")]
public string Reasoning { get; set; } = string.Empty;
[Category("03. General")]
public bool IsActive { get; set; } = true;
[Category("03. General")]
public bool IsHidden { get; set; } = false;
// Stats
[Category("04. Statistics")]
[ReadOnly(true)]
public int TotalTrades { get; set; } = 0;
[Category("04. Statistics")]
[ReadOnly(true)]
public int WinningTrades { get; set; } = 0;
[Category("04. Statistics")]
[ReadOnly(true)]
public double Winrate30t { get; set; } = 0.0;
[Category("04. Statistics")]
[ReadOnly(true)]
public double TotalPnl { get; set; } = 0.0;
[Browsable(false)]
public HashSet<int> AssignedAccountIds { get; set; } = new();
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace PolyTraderSharp.Models
{
public class TraderAnalyticsResult
{
public int AccountId { get; set; }
public int SourceTraderId { get; set; }
public string SourceTraderName { get; set; } = string.Empty;
public string SourceTraderAddress { get; set; } = string.Empty;
public decimal Winrate30T { get; set; }
public decimal Pnl30T { get; set; }
public int Trades7D { get; set; }
}
}