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
+161
View File
@@ -0,0 +1,161 @@
import requests
import argparse
import json
import os
import statistics
import datetime
def fetch_activity_3days(wallet):
all_trades = []
offset = 0
now_ts = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
three_days = 3 * 24 * 60 * 60
print(f"Fetching 3 days history for {wallet}...")
while True:
url = f"https://data-api.polymarket.com/activity?user={wallet}&limit=1000&offset={offset}"
try:
r = requests.get(url, timeout=15)
if r.status_code == 200:
data = r.json()
items = data if isinstance(data, list) else (data.get("value", data.get("data", [])) if isinstance(data, dict) else [])
if not items:
break
all_trades.extend(items)
# Check if we have passed 3 days
oldest_ts = items[-1].get("timestamp")
if oldest_ts and (now_ts - oldest_ts) >= three_days:
break
offset += 1000
else:
break
except Exception as e:
print(f"Error fetching {wallet}: {e}")
break
return all_trades
def analyze_trader(wallet, display_name):
trades = fetch_activity_3days(wallet)
if not trades:
return None
# Filter trades and sort ascending (oldest first)
valid_trades = [t for t in trades if t.get("type") == "TRADE" and t.get("timestamp") and t.get("asset")]
valid_trades.sort(key=lambda x: x["timestamp"])
# Group by asset
from collections import defaultdict
by_asset = defaultdict(list)
for t in valid_trades:
by_asset[t["asset"]].append(t)
total_evaluated = 0
snipes = 0
hold_times = []
for asset, asset_trades in by_asset.items():
# Find first BUY
buy_ts = None
for t in asset_trades:
if t["side"] == "BUY":
buy_ts = t["timestamp"]
break
if buy_ts is None:
continue
# Find first SELL after BUY (allow same second for immediate script-sells)
sell_ts = None
for t in asset_trades:
if t["side"] == "SELL" and t["timestamp"] >= buy_ts:
sell_ts = t["timestamp"]
break
if sell_ts is not None:
total_evaluated += 1
hold_dur = sell_ts - buy_ts
hold_times.append(hold_dur)
if hold_dur < 300: # Less than 5 minutes
snipes += 1
if total_evaluated == 0:
return {
"name": display_name,
"wallet": wallet,
"evaluated": 0,
"snipes": 0,
"ratio": 0.0,
"median": 0
}
ratio = (snipes / total_evaluated) * 100
median_hold = statistics.median(hold_times) if hold_times else 0
return {
"name": display_name,
"wallet": wallet,
"evaluated": total_evaluated,
"snipes": snipes,
"ratio": ratio,
"median": median_hold
}
def print_result(res):
print(f"Trader: {res['name']} ({res['wallet']})")
print(f" Evaluated Pairs: {res['evaluated']}")
print(f" Snipe Trades (<5m): {res['snipes']}")
if res['evaluated'] > 0:
print(f" Sniper Ratio: {res['ratio']:.2f}%")
print(f" Median Hold: {res['median']:.0f} seconds")
print("-" * 40)
def main():
parser = argparse.ArgumentParser(description="Analyze a trader for Liquidity Sniping.")
parser.add_argument("--wallet", type=str, help="Single wallet to analyze")
parser.add_argument("--all", action="store_true", help="Analyze all active traders in PolyTraderDB.trackers.json")
args = parser.parse_args()
if args.wallet:
res = analyze_trader(args.wallet, "CLI_TEST")
if res:
print_result(res)
elif args.all:
print("Analyzing all active traders...")
db_path = r"bin\Debug\net8.0-windows7.0\Logs\PolyTraderDB.trackers.json"
if not os.path.exists(db_path):
print(f"Could not find DB at {db_path}")
return
with open(db_path, "r", encoding="utf-8") as f:
data = json.load(f)
active_traders = [t for t in data if t.get("IsActive")]
print(f"Found {len(active_traders)} active traders.")
results = []
for t in active_traders:
wallet = t.get("WalletAddress")
name = t.get("DisplayName")
res = analyze_trader(wallet, name)
if res:
results.append(res)
# Sort by worst offenders (highest sniper ratio)
results.sort(key=lambda x: x["ratio"], reverse=True)
print("\n=== SNIPING REPORT ===")
print(f"{'Trader Name':<20} | {'Evaluated':<10} | {'Snipes':<8} | {'Ratio':<8} | {'Median Hold':<12}")
print("-" * 75)
for r in results:
if r['evaluated'] > 0:
print(f"{r['name']:<20} | {r['evaluated']:<10} | {r['snipes']:<8} | {r['ratio']:>5.1f}% | {r['median']:>5.0f} sec")
else:
print(f"{r['name']:<20} | {r['evaluated']:<10} | {r['snipes']:<8} | {'N/A':<8} | {'N/A':<12}")
if __name__ == "__main__":
main()