优化信号
This commit is contained in:
+1
-1
@@ -34,7 +34,7 @@ HTTP_PROXY=http://127.0.0.1:7890
|
||||
# TAVILY_API_KEY= # 网页搜索 (https://tavily.com)
|
||||
# TWITTER_API_KEY= # Twitter 社交情绪
|
||||
# SERPER_API_KEY= # 网页搜索备用 (https://serper.dev)
|
||||
# POLYGON_API_KEY= # 股票、外汇数据 (https://polygon.io)
|
||||
# POLYGON_API_KEY= # 股票、外汇数据 (https://polygon.io, 已更名为 massive.com)
|
||||
# FRED_API_KEY= # 美国经济指标 (https://fred.stlouisfed.org)
|
||||
# ETHERSCAN_API_KEY= # 链上数据 (https://etherscan.io)
|
||||
# CONGRESS_API_KEY= # 美国立法动态 (https://api.congress.gov)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://app.kilo.ai/config.json"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import sqlite3
|
||||
conn=sqlite3.connect('data/signals.db')
|
||||
c=conn.cursor()
|
||||
|
||||
# Trade size vs IAS relationship
|
||||
print("=== Trade Size vs IAS (by size bucket) ===")
|
||||
for lo,hi in [(0,2000),(2000,5000),(5000,10000),(10000,20000),(20000,50000),(50000,999999)]:
|
||||
row=c.execute('SELECT COUNT(*), AVG(information_asymmetry_score), AVG(trade_size_usd) FROM signals WHERE trade_size_usd>? AND trade_size_usd<=?',(lo,hi)).fetchone()
|
||||
n=row[0]
|
||||
if n>0:
|
||||
avg_i = round(row[1],3)
|
||||
avg_s = round(row[2],0)
|
||||
print(f" ${lo:,.0f}-${hi:,.0f}: {n:3d} sigs, avg IAS={avg_i:.3f}, avg size=${avg_s:,.0f}")
|
||||
|
||||
print()
|
||||
|
||||
# Market question frequency
|
||||
print("=== Top 10 Most Frequently Signaled Markets ===")
|
||||
for r in c.execute('SELECT market_question, COUNT(*) as cnt, AVG(information_asymmetry_score) as avg_i FROM signals GROUP BY market_question ORDER BY cnt DESC LIMIT 10').fetchall():
|
||||
print(f" {r[0][:65]:65s} | {r[1]:3d} sigs | avg IAS={r[2]:.3f}")
|
||||
|
||||
print()
|
||||
|
||||
# Resolution status
|
||||
print("=== Unresolved Signals (PENDING) ===")
|
||||
pending=c.execute('SELECT COUNT(*) FROM signals WHERE market_resolved IS NULL OR market_resolved=?',(0,)).fetchone()[0]
|
||||
print(f" Pending: {pending}")
|
||||
|
||||
print()
|
||||
|
||||
# Trader wallet frequency
|
||||
print("=== Top 10 Most Frequent Trader Wallets ===")
|
||||
for r in c.execute('SELECT trader_wallet, COUNT(*) as cnt, AVG(information_asymmetry_score) as avg_i FROM signals GROUP BY trader_wallet ORDER BY cnt DESC LIMIT 10').fetchall():
|
||||
print(f" {str(r[0])[:25]:25s} | {r[1]:3d} sigs | avg IAS={r[2]:.3f}")
|
||||
@@ -0,0 +1,58 @@
|
||||
import sqlite3, json
|
||||
conn=sqlite3.connect('data/signals.db')
|
||||
c=conn.cursor()
|
||||
|
||||
print("="*60)
|
||||
print("SIGNALS DATABASE ANALYSIS")
|
||||
print("="*60)
|
||||
|
||||
total=c.execute('SELECT COUNT(*) FROM signals').fetchone()[0]
|
||||
resolved=c.execute('SELECT COUNT(*) FROM signals WHERE market_resolved=?',(1,)).fetchone()[0]
|
||||
correct=c.execute('SELECT COUNT(*) FROM signals WHERE signal_correct=?',(1,)).fetchone()[0]
|
||||
incorrect=c.execute('SELECT COUNT(*) FROM signals WHERE signal_correct=?',(0,)).fetchone()[0]
|
||||
|
||||
print(f"\nTotal signals: {total}")
|
||||
print(f"Resolved: {resolved} | Correct: {correct} | Incorrect: {incorrect}")
|
||||
print(f"Win rate: {correct/resolved:.2%}")
|
||||
print(f"Avg ROI: {c.execute('SELECT AVG(theoretical_roi) FROM signals WHERE market_resolved=?',(1,)).fetchone()[0]:.2%}")
|
||||
|
||||
print("\n=== IAS Distribution ===")
|
||||
for lo,hi in [(0.0,0.3),(0.3,0.4),(0.4,0.5),(0.5,0.6),(0.6,0.7),(0.7,0.8),(0.8,1.0)]:
|
||||
row=c.execute('SELECT COUNT(*), AVG(information_asymmetry_score) FROM signals WHERE information_asymmetry_score>? AND information_asymmetry_score<=?',(lo,hi)).fetchone()
|
||||
n=row[0]; avg=round(row[1],3) if row[1] else 0
|
||||
bar='#'*int(n*0.4)
|
||||
print(f" {lo}-{hi}: {n:3d} signals, avg={avg:.3f} {bar}")
|
||||
|
||||
print("\n=== Win Rate by IAS Tier ===")
|
||||
for lo,hi in [(0.3,0.4),(0.4,0.5),(0.5,0.6),(0.6,0.7),(0.7,0.8),(0.8,1.0)]:
|
||||
n=c.execute('SELECT COUNT(*) FROM signals WHERE information_asymmetry_score>? AND information_asymmetry_score<=?',(lo,hi)).fetchone()[0]
|
||||
if n>0:
|
||||
cr=c.execute('SELECT COUNT(*) FROM signals WHERE information_asymmetry_score>? AND information_asymmetry_score<=? AND signal_correct=?',(lo,hi,1)).fetchone()[0]
|
||||
print(f" IAS {lo}-{hi}: {cr}/{n} correct ({cr/n:.1%})")
|
||||
|
||||
print("\n=== Trade Size Distribution ===")
|
||||
bins=[(0,1000),(1000,2000),(2000,3000),(3000,5000),(5000,10000),(10000,20000),(20000,50000),(50000,999999)]
|
||||
for lo,hi in bins:
|
||||
row=c.execute('SELECT COUNT(*), AVG(trade_size_usd) FROM signals WHERE trade_size_usd>? AND trade_size_usd<=?',(lo,hi)).fetchone()
|
||||
n=row[0]; avg=round(row[1],0) if row[1] else 0
|
||||
if n>0:
|
||||
print(f" ${lo:,.0f}-${hi:,.0f}: {n:3d} signals, avg ${avg:,.0f}")
|
||||
|
||||
print("\n=== Signal Time Range ===")
|
||||
earliest=c.execute('SELECT MIN(detected_at) FROM signals').fetchone()[0]
|
||||
latest=c.execute('SELECT MAX(detected_at) FROM signals').fetchone()[0]
|
||||
print(f" First: {earliest}")
|
||||
print(f" Last: {latest}")
|
||||
|
||||
print("\n=== Top 10 Signals by IAS ===")
|
||||
for r in c.execute('SELECT trade_side, trade_outcome, trade_size_usd, trade_price, market_question, information_asymmetry_score, signal_correct, theoretical_roi FROM signals ORDER BY information_asymmetry_score DESC LIMIT 10').fetchall():
|
||||
c_str='CORRECT' if r[6] else ('WRONG' if r[6] is not None else 'PENDING')
|
||||
roi=f'{r[7]:.2%}' if r[7] else 'N/A'
|
||||
print(f" IAS={r[5]:.2f} | {r[0]} {r[1]} @ {r[3]:.4f} ${r[2]:,.0f} | {r[4][:55]}... [{c_str}] ROI={roi}")
|
||||
|
||||
print("\n=== Sample LLM Analysis Reasoning (highest IAS) ===")
|
||||
top=c.execute('SELECT reasoning, insider_evidence FROM signals ORDER BY information_asymmetry_score DESC LIMIT 3').fetchall()
|
||||
for i, (reasoning, evidence) in enumerate(top):
|
||||
print(f"\n--- Signal #{i+1} ---")
|
||||
print(f"Reasoning (first 500 chars): {str(reasoning)[:500]}")
|
||||
print(f"Insider evidence: {str(evidence)[:500] if evidence else 'None'}")
|
||||
@@ -0,0 +1,78 @@
|
||||
import json, collections, math
|
||||
from datetime import datetime
|
||||
|
||||
with open('data/processed_transactions.json') as f:
|
||||
txns = json.load(f)
|
||||
|
||||
print(f"Total transactions in file: {len(txns)}")
|
||||
print()
|
||||
|
||||
# Sample
|
||||
print("=== Sample (first 3) ===")
|
||||
for t in txns[:3]:
|
||||
print(json.dumps(t, indent=2))
|
||||
print()
|
||||
|
||||
# Fields available
|
||||
print("=== Available Fields ===")
|
||||
sample = txns[0]
|
||||
print(list(sample.keys()))
|
||||
print()
|
||||
|
||||
# Direction distribution
|
||||
print("=== Direction ===")
|
||||
dirs = collections.Counter()
|
||||
for t in txns:
|
||||
dirs[t.get('side','?')]+=1
|
||||
print(dirs)
|
||||
print()
|
||||
|
||||
# Side breakdown
|
||||
print("=== BUY vs SELL ===")
|
||||
for s in ['BUY','SELL']:
|
||||
n=sum(1 for t in txns if t.get('side')==s)
|
||||
print(f" {s}: {n}")
|
||||
print()
|
||||
|
||||
# Size distribution
|
||||
print("=== Trade Size (USD) Distribution ===")
|
||||
bins=[(0,100),(100,500),(500,1000),(1000,2000),(2000,5000),(5000,10000),(10000,20000),(20000,50000),(50000,100000),(100000,999999)]
|
||||
for lo,hi in bins:
|
||||
n=sum(1 for t in txns if lo<t.get('usdc_size',0)<=hi)
|
||||
if n>0:
|
||||
avg=sum(t.get('usdc_size',0) for t in txns if lo<t.get('usdc_size',0)<=hi)/n
|
||||
print(f" ${lo:,.0f}-${hi:,.0f}: {n} txns, avg ${avg:,.0f}")
|
||||
print()
|
||||
|
||||
# Price distribution
|
||||
print("=== Price Distribution (BUY only) ===")
|
||||
buy_txns=[t for t in txns if t.get('side')=='BUY']
|
||||
price_bins=[(0,0.1),(0.1,0.2),(0.2,0.3),(0.3,0.4),(0.4,0.5),(0.5,0.6),(0.6,0.7),(0.7,0.8),(0.8,0.9),(0.9,1.0)]
|
||||
for lo,hi in price_bins:
|
||||
n=sum(1 for t in buy_txns if lo<=t.get('price',0)<hi)
|
||||
if n>0:
|
||||
print(f" {lo}-{hi}: {n}")
|
||||
print()
|
||||
|
||||
# Largest trades
|
||||
print("=== Top 20 Largest Trades (BUY) ===")
|
||||
largest=sorted(buy_txns, key=lambda t: t.get('usdc_size',0), reverse=True)[:20]
|
||||
for t in largest:
|
||||
print(f" ${t['usdc_size']:,.0f} | {t['side']} {t.get('outcome','?')} @ {t['price']:.4f} | {t.get('title','?')[:60]}")
|
||||
print()
|
||||
|
||||
# Check what happens at each filter stage
|
||||
print("=== Filter Stage Analysis (BUY only, 0.0-0.95 price) ===")
|
||||
print(f"BUY txns with price in 0.0-0.95: {sum(1 for t in buy_txns if 0<=t.get('price',0)<=0.95)}")
|
||||
print(f"BUY txns size >= 1000: {sum(1 for t in buy_txns if t.get('usdc_size',0)>=1000)}")
|
||||
print(f"BUY txns size >= 3000: {sum(1 for t in buy_txns if t.get('usdc_size',0)>=3000)}")
|
||||
print(f"BUY txns size >= 5000: {sum(1 for t in buy_txns if t.get('usdc_size',0)>=5000)}")
|
||||
print()
|
||||
|
||||
# Check if there are BUY txns >= 5000 with price in range
|
||||
big_buy=[t for t in buy_txns if t.get('usdc_size',0)>=5000 and 0<=t.get('price',0)<=0.95]
|
||||
print(f"BUY txns >= $5K and price in range: {len(big_buy)}")
|
||||
if big_buy:
|
||||
print(" Sample of qualifying transactions:")
|
||||
for t in big_buy[:5]:
|
||||
print(f" ${t['usdc_size']:,.0f} @ {t['price']:.4f} | vol={t.get('volume',0):,.0f}")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -56,6 +56,7 @@ class Settings(BaseSettings):
|
||||
min_trade_size_usd: float = Field(default=1000.0, alias="MIN_TRADE_SIZE_USD")
|
||||
min_price: float = Field(default=0.10, alias="MIN_PRICE")
|
||||
max_price: float = Field(default=0.90, alias="MAX_PRICE")
|
||||
premium_threshold: float = Field(default=0.01, alias="PREMIUM_THRESHOLD")
|
||||
|
||||
# Monitoring Settings
|
||||
trending_markets_limit: int = Field(default=50, alias="TRENDING_MARKETS_LIMIT")
|
||||
|
||||
@@ -254,16 +254,16 @@ class TradeMonitor:
|
||||
pass
|
||||
|
||||
# --- 4. Size ---
|
||||
if activity.usdc_size < 3_000:
|
||||
if activity.usdc_size < self.settings.min_trade_size_usd:
|
||||
return False
|
||||
|
||||
# --- 5. Dynamic size ---
|
||||
base_size = 5_000.0
|
||||
base_size = max(self.settings.min_trade_size_usd, 5_000.0)
|
||||
baseline_volume = 1_000_000.0
|
||||
|
||||
if market and market.volume > 0:
|
||||
threshold = base_size * math.sqrt(market.volume / baseline_volume)
|
||||
threshold = max(3_000.0, min(threshold, 50_000.0))
|
||||
if market and market.volume_24hr > 0:
|
||||
threshold = base_size * math.sqrt(market.volume_24hr / baseline_volume)
|
||||
threshold = max(self.settings.min_trade_size_usd, min(threshold, 50_000.0))
|
||||
else:
|
||||
threshold = base_size
|
||||
|
||||
@@ -271,12 +271,9 @@ class TradeMonitor:
|
||||
return False
|
||||
|
||||
# --- 5.5 Normalized size (like normalized_premium) ---
|
||||
# usdc_size / √(volume) makes signals comparable across market sizes.
|
||||
# A $5K trade in a $50K market is far more significant than $20K in a $10M market.
|
||||
if market and market.volume > 0:
|
||||
normalized = activity.usdc_size / math.sqrt(market.volume)
|
||||
# Minimum normalized threshold: filters out trades that are trivial
|
||||
# relative to market size (calibrated: $5K in a $1M market → 5.0)
|
||||
# Use 24h volume so old markets don't suppress small trades.
|
||||
if market and market.volume_24hr > 0:
|
||||
normalized = activity.usdc_size / math.sqrt(market.volume_24hr)
|
||||
if normalized < 1.5:
|
||||
return False
|
||||
|
||||
@@ -289,7 +286,7 @@ class TradeMonitor:
|
||||
else:
|
||||
market_mid = 1.0 - market.outcome_prices[0]
|
||||
|
||||
if activity.price < market_mid + 0.01:
|
||||
if activity.price < market_mid + self.settings.premium_threshold:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user