@gonzih/polymarket-arb 1.0.12 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backtest.d.ts +77 -88
- package/dist/backtest.d.ts.map +1 -1
- package/dist/backtest.js +200 -385
- package/dist/backtest.js.map +1 -1
- package/dist/backtestRunner.d.ts.map +1 -1
- package/dist/backtestRunner.js +61 -154
- package/dist/backtestRunner.js.map +1 -1
- package/package.json +1 -1
package/dist/backtest.d.ts
CHANGED
|
@@ -1,111 +1,100 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export type PricePoint = {
|
|
15
|
-
t: number;
|
|
16
|
-
p: number;
|
|
17
|
-
};
|
|
18
|
-
export type BacktestSignal = {
|
|
1
|
+
export declare const COINBASE_API = "https://api.exchange.coinbase.com";
|
|
2
|
+
export declare const CLOB_API = "https://clob.polymarket.com";
|
|
3
|
+
export declare const MOMENTUM_THRESHOLD = 0.015;
|
|
4
|
+
export declare const CORRELATION_THRESHOLD = 0.02;
|
|
5
|
+
export declare const CORRELATION_WINDOW_MINUTES = 30;
|
|
6
|
+
export type Candle = [number, number, number, number, number, number];
|
|
7
|
+
export declare const CANDLE_TIME = 0;
|
|
8
|
+
export declare const CANDLE_LOW = 1;
|
|
9
|
+
export declare const CANDLE_HIGH = 2;
|
|
10
|
+
export declare const CANDLE_OPEN = 3;
|
|
11
|
+
export declare const CANDLE_CLOSE = 4;
|
|
12
|
+
export declare const CANDLE_VOL = 5;
|
|
13
|
+
export type CandleSignal = {
|
|
19
14
|
firedAt: number;
|
|
20
|
-
|
|
21
|
-
direction: "
|
|
15
|
+
symbol: string;
|
|
16
|
+
direction: "UP" | "DOWN";
|
|
22
17
|
momentum: number;
|
|
18
|
+
price: number;
|
|
19
|
+
confidence: number;
|
|
23
20
|
};
|
|
24
|
-
export type
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
question: string;
|
|
28
|
-
signalFiredAt: number;
|
|
29
|
-
oddsAtSignal: number;
|
|
30
|
-
claudeDecision: ClaudeDecision;
|
|
31
|
-
claudeLatencyMs: number;
|
|
32
|
-
actualResolution: number;
|
|
33
|
-
correct: boolean;
|
|
34
|
-
kellySizePct: number;
|
|
35
|
-
hypotheticalPnl: number;
|
|
21
|
+
export type RawTrade = {
|
|
22
|
+
price: string | number;
|
|
23
|
+
timestamp: string | number;
|
|
36
24
|
};
|
|
37
|
-
export type
|
|
25
|
+
export type PolymarketMarket = {
|
|
38
26
|
id: string;
|
|
39
27
|
conditionId: string;
|
|
40
28
|
clobTokenId: string;
|
|
41
29
|
question: string;
|
|
42
|
-
volume: number;
|
|
43
|
-
endDate: number;
|
|
44
30
|
yesPrice: number;
|
|
31
|
+
volume: number;
|
|
32
|
+
};
|
|
33
|
+
export type OddsMove = {
|
|
34
|
+
marketId: string;
|
|
35
|
+
question: string;
|
|
36
|
+
oddsChange: number;
|
|
37
|
+
direction: "UP" | "DOWN";
|
|
38
|
+
};
|
|
39
|
+
export type SignalResult = {
|
|
40
|
+
signal: CandleSignal;
|
|
41
|
+
marketsChecked: number;
|
|
42
|
+
correlatedMoves: OddsMove[];
|
|
43
|
+
};
|
|
44
|
+
export type BacktestReport = {
|
|
45
|
+
date: string;
|
|
46
|
+
product: string;
|
|
47
|
+
candlesAnalyzed: number;
|
|
48
|
+
signalsFired: number;
|
|
49
|
+
signalRatePerDay: number;
|
|
50
|
+
marketsChecked: number;
|
|
51
|
+
correlatedSignals: number;
|
|
52
|
+
correlationRate: number;
|
|
53
|
+
signals: SignalResult[];
|
|
54
|
+
claudeInterpretation: string;
|
|
45
55
|
};
|
|
46
|
-
export declare function fetchResolvedMarkets(limit?: number): Promise<ResolvedMarket[]>;
|
|
47
56
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
57
|
+
* Fetch 1-minute (or custom granularity) OHLCV candles from Coinbase REST API.
|
|
58
|
+
* Coinbase returns newest-first; we reverse to chronological order.
|
|
50
59
|
*/
|
|
51
|
-
export declare function
|
|
60
|
+
export declare function fetchCoinbaseCandles(product?: string, granularity?: number, limit?: number): Promise<Candle[]>;
|
|
52
61
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* empty data for resolved/closed markets. Falls back to trades reconstruction
|
|
56
|
-
* when the primary source returns fewer than 5 points.
|
|
57
|
-
* marketId should be a clobTokenId (the long numeric string from clobTokenIds[0]).
|
|
62
|
+
* Replay the 1.5% momentum signal logic against Coinbase candle data.
|
|
63
|
+
* Uses per-candle momentum (open→close). Applies 5-minute per-direction cooldown.
|
|
58
64
|
*/
|
|
59
|
-
export declare function
|
|
60
|
-
export declare function fetchActiveMarkets(limit?: number): Promise<ActiveMarket[]>;
|
|
65
|
+
export declare function replaySignals(candles: Candle[], symbol?: string): CandleSignal[];
|
|
61
66
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
67
|
+
* Fetch active Polymarket markets from the CLOB API.
|
|
68
|
+
* Handles both array and {data:[]} response shapes.
|
|
64
69
|
*/
|
|
65
|
-
export declare function
|
|
66
|
-
success: number;
|
|
67
|
-
errors: number;
|
|
68
|
-
avgLatencyMs: number;
|
|
69
|
-
sample: BacktestResult[];
|
|
70
|
-
}>;
|
|
70
|
+
export declare function fetchPolymarketMarkets(limit?: number): Promise<PolymarketMarket[]>;
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* window and 5% threshold suited to hourly prediction market data (0-1 price range).
|
|
72
|
+
* Fetch recent trades for a Polymarket market token from the CLOB.
|
|
73
|
+
* Returns empty array on any error.
|
|
75
74
|
*/
|
|
76
|
-
export declare function
|
|
75
|
+
export declare function fetchMarketTrades(tokenId: string): Promise<RawTrade[]>;
|
|
77
76
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
77
|
+
* For each signal, check if any Polymarket market moved >2% in odds
|
|
78
|
+
* within `windowMinutes` of the signal firing.
|
|
79
|
+
* tradesByMarket is a pre-fetched map of marketId → trades.
|
|
81
80
|
*/
|
|
82
|
-
export declare function
|
|
83
|
-
export declare function computePnl(decision: ClaudeDecision, odds: number, resolution: number, kellySizePct: number): number;
|
|
81
|
+
export declare function findCorrelatedMoves(signal: CandleSignal, markets: PolymarketMarket[], tradesByMarket: Record<string, RawTrade[]>, oddsThreshold?: number, windowMinutes?: number): OddsMove[];
|
|
84
82
|
/**
|
|
85
|
-
*
|
|
86
|
-
* because when spawned with an open stdin pipe the CLI waits for input otherwise.
|
|
83
|
+
* Build a human-readable signal log for Claude interpretation.
|
|
87
84
|
*/
|
|
88
|
-
export declare function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
passCount: number;
|
|
104
|
-
avgKellyPct: number;
|
|
105
|
-
totalPnl: number;
|
|
106
|
-
results: BacktestResult[];
|
|
107
|
-
}
|
|
108
|
-
export declare function generateReport(results: BacktestResult[], marketsAnalyzed: number): BacktestReport;
|
|
109
|
-
export declare function formatReport(report: BacktestReport, date: string): string;
|
|
110
|
-
export declare function writeReport(text: string, date: string): string;
|
|
85
|
+
export declare function buildSignalLog(results: SignalResult[]): string;
|
|
86
|
+
/**
|
|
87
|
+
* Spawn claude --print and ask for signal pattern analysis.
|
|
88
|
+
* Returns Claude's response text or a fallback message on failure.
|
|
89
|
+
*/
|
|
90
|
+
export declare function askClaude(signalLog: string): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Render the full backtest report as Markdown.
|
|
93
|
+
*/
|
|
94
|
+
export declare function generateMarkdownReport(report: BacktestReport): string;
|
|
95
|
+
/**
|
|
96
|
+
* Write a report to disk. Creates `dir` if it doesn't exist.
|
|
97
|
+
* Returns the path written.
|
|
98
|
+
*/
|
|
99
|
+
export declare function writeReport(text: string, date: string, dir?: string): string;
|
|
111
100
|
//# sourceMappingURL=backtest.d.ts.map
|
package/dist/backtest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backtest.d.ts","sourceRoot":"","sources":["../src/backtest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"backtest.d.ts","sourceRoot":"","sources":["../src/backtest.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY,sCAAsC,CAAC;AAChE,eAAO,MAAM,QAAQ,gCAAgC,CAAC;AACtD,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAG7C,MAAM,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtE,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,QAAQ,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,SAAY,EACnB,WAAW,SAAK,EAChB,KAAK,SAAM,GACV,OAAO,CAAC,MAAM,EAAE,CAAC,CAenB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,SAAY,GAAG,YAAY,EAAE,CAgCnF;AAqBD;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA8BpF;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAU5E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAC1C,aAAa,SAAwB,EACrC,aAAa,SAA6B,GACzC,QAAQ,EAAE,CA8BZ;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CA6B9D;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0ClE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAkCrE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM,CAOhF"}
|
package/dist/backtest.js
CHANGED
|
@@ -1,12 +1,72 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
3
4
|
import { log } from "./logger.js";
|
|
4
|
-
const
|
|
5
|
-
const CLOB_API = "https://clob.polymarket.com";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export const
|
|
9
|
-
export const
|
|
5
|
+
export const COINBASE_API = "https://api.exchange.coinbase.com";
|
|
6
|
+
export const CLOB_API = "https://clob.polymarket.com";
|
|
7
|
+
export const MOMENTUM_THRESHOLD = 0.015; // 1.5% per candle (open→close)
|
|
8
|
+
export const CORRELATION_THRESHOLD = 0.02; // 2% odds move
|
|
9
|
+
export const CORRELATION_WINDOW_MINUTES = 30;
|
|
10
|
+
export const CANDLE_TIME = 0;
|
|
11
|
+
export const CANDLE_LOW = 1;
|
|
12
|
+
export const CANDLE_HIGH = 2;
|
|
13
|
+
export const CANDLE_OPEN = 3;
|
|
14
|
+
export const CANDLE_CLOSE = 4;
|
|
15
|
+
export const CANDLE_VOL = 5;
|
|
16
|
+
/**
|
|
17
|
+
* Fetch 1-minute (or custom granularity) OHLCV candles from Coinbase REST API.
|
|
18
|
+
* Coinbase returns newest-first; we reverse to chronological order.
|
|
19
|
+
*/
|
|
20
|
+
export async function fetchCoinbaseCandles(product = "BTC-USD", granularity = 60, limit = 300) {
|
|
21
|
+
try {
|
|
22
|
+
const url = `${COINBASE_API}/products/${encodeURIComponent(product)}/candles?granularity=${granularity}&limit=${limit}`;
|
|
23
|
+
const res = await fetch(url);
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
log("warn", { source: "backtest", event: "coinbase_candles_error", status: res.status });
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
const data = (await res.json());
|
|
29
|
+
// Reverse so index 0 is oldest
|
|
30
|
+
return data.reverse();
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
log("warn", { source: "backtest", event: "coinbase_candles_exception", error: String(err) });
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Replay the 1.5% momentum signal logic against Coinbase candle data.
|
|
39
|
+
* Uses per-candle momentum (open→close). Applies 5-minute per-direction cooldown.
|
|
40
|
+
*/
|
|
41
|
+
export function replaySignals(candles, symbol = "BTC-USD") {
|
|
42
|
+
const signals = [];
|
|
43
|
+
const COOLDOWN_MS = 5 * 60 * 1000;
|
|
44
|
+
const lastSignalTime = { UP: 0, DOWN: 0 };
|
|
45
|
+
for (const candle of candles) {
|
|
46
|
+
const open = candle[CANDLE_OPEN];
|
|
47
|
+
const close = candle[CANDLE_CLOSE];
|
|
48
|
+
const ts = candle[CANDLE_TIME];
|
|
49
|
+
if (open === 0)
|
|
50
|
+
continue;
|
|
51
|
+
const momentum = (close - open) / open;
|
|
52
|
+
if (Math.abs(momentum) < MOMENTUM_THRESHOLD)
|
|
53
|
+
continue;
|
|
54
|
+
const direction = momentum > 0 ? "UP" : "DOWN";
|
|
55
|
+
const firedAt = ts * 1000;
|
|
56
|
+
if (firedAt - lastSignalTime[direction] < COOLDOWN_MS)
|
|
57
|
+
continue;
|
|
58
|
+
lastSignalTime[direction] = firedAt;
|
|
59
|
+
signals.push({
|
|
60
|
+
firedAt,
|
|
61
|
+
symbol,
|
|
62
|
+
direction,
|
|
63
|
+
momentum,
|
|
64
|
+
price: close,
|
|
65
|
+
confidence: Math.min(1, Math.abs(momentum) / (MOMENTUM_THRESHOLD * 2)),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return signals;
|
|
69
|
+
}
|
|
10
70
|
function parseJsonField(field) {
|
|
11
71
|
if (Array.isArray(field))
|
|
12
72
|
return field;
|
|
@@ -17,446 +77,201 @@ function parseJsonField(field) {
|
|
|
17
77
|
return [];
|
|
18
78
|
}
|
|
19
79
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const res = await fetch(url);
|
|
32
|
-
if (!res.ok) {
|
|
33
|
-
log("warn", { source: "backtest", event: "fetch_resolved_error", status: res.status });
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
markets = (await res.json());
|
|
37
|
-
}
|
|
38
|
-
catch (err) {
|
|
39
|
-
log("warn", { source: "backtest", event: "fetch_resolved_exception", error: String(err) });
|
|
40
|
-
break;
|
|
80
|
+
/**
|
|
81
|
+
* Fetch active Polymarket markets from the CLOB API.
|
|
82
|
+
* Handles both array and {data:[]} response shapes.
|
|
83
|
+
*/
|
|
84
|
+
export async function fetchPolymarketMarkets(limit = 20) {
|
|
85
|
+
try {
|
|
86
|
+
const url = `${CLOB_API}/markets?active=true&closed=false&limit=${limit}`;
|
|
87
|
+
const res = await fetch(url);
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
log("warn", { source: "backtest", event: "polymarket_markets_error", status: res.status });
|
|
90
|
+
return [];
|
|
41
91
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (volume < 50_000)
|
|
47
|
-
continue;
|
|
48
|
-
const endDate = m.endDate ? new Date(m.endDate).getTime() : 0;
|
|
49
|
-
if (endDate < sixMonthsAgo || endDate === 0)
|
|
50
|
-
continue;
|
|
51
|
-
// Only include cleanly resolved markets (YES price = 0 or 1)
|
|
92
|
+
const raw = (await res.json());
|
|
93
|
+
const markets = Array.isArray(raw) ? raw : (raw.data ?? []);
|
|
94
|
+
return markets
|
|
95
|
+
.map((m) => {
|
|
52
96
|
const prices = parseJsonField(m.outcomePrices ?? []).map(Number);
|
|
53
|
-
|
|
54
|
-
continue;
|
|
55
|
-
const yesPrice = prices[0];
|
|
56
|
-
if (yesPrice !== 0 && yesPrice !== 1)
|
|
57
|
-
continue;
|
|
58
|
-
// Parse YES outcome clobTokenId for CLOB price history
|
|
97
|
+
const yesPrice = prices[0] ?? 0.5;
|
|
59
98
|
const tokenIds = parseJsonField(m.clobTokenIds ?? "[]");
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
clobTokenId,
|
|
99
|
+
return {
|
|
100
|
+
id: m.id ?? "",
|
|
101
|
+
conditionId: m.conditionId ?? m.id ?? "",
|
|
102
|
+
clobTokenId: tokenIds[0] ?? "",
|
|
65
103
|
question: m.question ?? "",
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
offset += batchSize;
|
|
76
|
-
if (markets.length < batchSize)
|
|
77
|
-
break; // no more pages
|
|
104
|
+
yesPrice,
|
|
105
|
+
volume: Number(m.volumeNum ?? m.volume ?? 0),
|
|
106
|
+
};
|
|
107
|
+
})
|
|
108
|
+
.filter((m) => m.id && m.question && m.volume > 10_000);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
log("warn", { source: "backtest", event: "polymarket_markets_exception", error: String(err) });
|
|
112
|
+
return [];
|
|
78
113
|
}
|
|
79
|
-
log("info", {
|
|
80
|
-
source: "backtest",
|
|
81
|
-
event: "resolved_markets_fetched",
|
|
82
|
-
count: results.length,
|
|
83
|
-
});
|
|
84
|
-
return results;
|
|
85
114
|
}
|
|
86
115
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
116
|
+
* Fetch recent trades for a Polymarket market token from the CLOB.
|
|
117
|
+
* Returns empty array on any error.
|
|
89
118
|
*/
|
|
90
|
-
export async function
|
|
119
|
+
export async function fetchMarketTrades(tokenId) {
|
|
91
120
|
try {
|
|
92
|
-
const url = `${CLOB_API}/trades?market=${encodeURIComponent(
|
|
121
|
+
const url = `${CLOB_API}/trades?market=${encodeURIComponent(tokenId)}&limit=500`;
|
|
93
122
|
const res = await fetch(url);
|
|
94
123
|
if (!res.ok)
|
|
95
124
|
return [];
|
|
96
125
|
const raw = (await res.json());
|
|
97
|
-
|
|
98
|
-
const buckets = new Map();
|
|
99
|
-
for (const trade of trades) {
|
|
100
|
-
const ts = Number(trade.timestamp);
|
|
101
|
-
const tsSec = ts < 1e12 ? ts : Math.floor(ts / 1000);
|
|
102
|
-
const bucket = Math.floor(tsSec / 3600) * 3600;
|
|
103
|
-
buckets.set(bucket, Number(trade.price));
|
|
104
|
-
}
|
|
105
|
-
return Array.from(buckets.entries())
|
|
106
|
-
.map(([t, p]) => ({ t, p }))
|
|
107
|
-
.sort((a, b) => a.t - b.t);
|
|
126
|
+
return Array.isArray(raw) ? raw : (raw.data ?? []);
|
|
108
127
|
}
|
|
109
128
|
catch {
|
|
110
129
|
return [];
|
|
111
130
|
}
|
|
112
131
|
}
|
|
113
132
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* when the primary source returns fewer than 5 points.
|
|
118
|
-
* marketId should be a clobTokenId (the long numeric string from clobTokenIds[0]).
|
|
133
|
+
* For each signal, check if any Polymarket market moved >2% in odds
|
|
134
|
+
* within `windowMinutes` of the signal firing.
|
|
135
|
+
* tradesByMarket is a pre-fetched map of marketId → trades.
|
|
119
136
|
*/
|
|
120
|
-
export
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return primaryHistory;
|
|
143
|
-
}
|
|
144
|
-
export async function fetchActiveMarkets(limit = 50) {
|
|
145
|
-
const results = [];
|
|
146
|
-
let offset = 0;
|
|
147
|
-
const batchSize = 100;
|
|
148
|
-
while (results.length < limit) {
|
|
149
|
-
const url = `${GAMMA_API}/markets?closed=false&active=true&limit=${batchSize}&offset=${offset}`;
|
|
150
|
-
let markets;
|
|
151
|
-
try {
|
|
152
|
-
const res = await fetch(url);
|
|
153
|
-
if (!res.ok) {
|
|
154
|
-
log("warn", { source: "backtest", event: "fetch_active_error", status: res.status });
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
markets = (await res.json());
|
|
158
|
-
}
|
|
159
|
-
catch (err) {
|
|
160
|
-
log("warn", { source: "backtest", event: "fetch_active_exception", error: String(err) });
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
if (markets.length === 0)
|
|
164
|
-
break;
|
|
165
|
-
for (const m of markets) {
|
|
166
|
-
const volume = Number(m.volumeNum ?? m.volume ?? 0);
|
|
167
|
-
if (volume < 50_000)
|
|
168
|
-
continue;
|
|
169
|
-
const endDate = m.endDate ? new Date(m.endDate).getTime() : 0;
|
|
170
|
-
if (endDate === 0)
|
|
171
|
-
continue;
|
|
172
|
-
const prices = parseJsonField(m.outcomePrices ?? []).map(Number);
|
|
173
|
-
if (prices.length < 2)
|
|
174
|
-
continue;
|
|
175
|
-
const yesPrice = prices[0];
|
|
176
|
-
if (yesPrice < 0.05 || yesPrice > 0.95)
|
|
177
|
-
continue;
|
|
178
|
-
const tokenIds = parseJsonField(m.clobTokenIds ?? "[]");
|
|
179
|
-
const clobTokenId = tokenIds[0] ?? "";
|
|
180
|
-
results.push({
|
|
181
|
-
id: m.id,
|
|
182
|
-
conditionId: m.conditionId ?? m.id,
|
|
183
|
-
clobTokenId,
|
|
184
|
-
question: m.question ?? "",
|
|
185
|
-
volume,
|
|
186
|
-
endDate,
|
|
187
|
-
yesPrice,
|
|
137
|
+
export function findCorrelatedMoves(signal, markets, tradesByMarket, oddsThreshold = CORRELATION_THRESHOLD, windowMinutes = CORRELATION_WINDOW_MINUTES) {
|
|
138
|
+
const windowStartSec = signal.firedAt / 1000;
|
|
139
|
+
const windowEndSec = windowStartSec + windowMinutes * 60;
|
|
140
|
+
const correlated = [];
|
|
141
|
+
for (const market of markets) {
|
|
142
|
+
const trades = tradesByMarket[market.id] ?? [];
|
|
143
|
+
const windowTrades = trades.filter((t) => {
|
|
144
|
+
const ts = Number(t.timestamp);
|
|
145
|
+
const tsSec = ts < 1e12 ? ts : Math.floor(ts / 1000);
|
|
146
|
+
return tsSec >= windowStartSec && tsSec <= windowEndSec;
|
|
147
|
+
});
|
|
148
|
+
if (windowTrades.length < 2)
|
|
149
|
+
continue;
|
|
150
|
+
const priceStart = Number(windowTrades[0].price);
|
|
151
|
+
const priceEnd = Number(windowTrades[windowTrades.length - 1].price);
|
|
152
|
+
const oddsChange = priceEnd - priceStart;
|
|
153
|
+
if (Math.abs(oddsChange) >= oddsThreshold) {
|
|
154
|
+
correlated.push({
|
|
155
|
+
marketId: market.id,
|
|
156
|
+
question: market.question,
|
|
157
|
+
oddsChange: Math.abs(oddsChange),
|
|
158
|
+
direction: oddsChange > 0 ? "UP" : "DOWN",
|
|
188
159
|
});
|
|
189
|
-
if (results.length >= limit)
|
|
190
|
-
break;
|
|
191
160
|
}
|
|
192
|
-
offset += batchSize;
|
|
193
|
-
if (markets.length < batchSize)
|
|
194
|
-
break;
|
|
195
161
|
}
|
|
196
|
-
|
|
197
|
-
return results;
|
|
162
|
+
return correlated;
|
|
198
163
|
}
|
|
199
164
|
/**
|
|
200
|
-
*
|
|
201
|
-
* Used when price history is unavailable and no momentum signals can be replayed.
|
|
165
|
+
* Build a human-readable signal log for Claude interpretation.
|
|
202
166
|
*/
|
|
203
|
-
export
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
let totalLatency = 0;
|
|
207
|
-
let errors = 0;
|
|
208
|
-
for (const market of sample) {
|
|
209
|
-
// Use last-known odds as 0.5 (unknown pre-resolution for closed markets)
|
|
210
|
-
const odds = 0.5;
|
|
211
|
-
const { decision, latencyMs } = await askClaude(market.question, odds);
|
|
212
|
-
totalLatency += latencyMs;
|
|
213
|
-
if (decision === "ERROR")
|
|
214
|
-
errors++;
|
|
215
|
-
const correct = decision === "BUY_YES"
|
|
216
|
-
? market.resolution === 1
|
|
217
|
-
: decision === "BUY_NO"
|
|
218
|
-
? market.resolution === 0
|
|
219
|
-
: false;
|
|
220
|
-
results.push({
|
|
221
|
-
marketId: market.id,
|
|
222
|
-
question: market.question,
|
|
223
|
-
signalFiredAt: 0,
|
|
224
|
-
oddsAtSignal: odds,
|
|
225
|
-
claudeDecision: decision,
|
|
226
|
-
claudeLatencyMs: latencyMs,
|
|
227
|
-
actualResolution: market.resolution,
|
|
228
|
-
correct,
|
|
229
|
-
kellySizePct: 0,
|
|
230
|
-
hypotheticalPnl: 0,
|
|
231
|
-
});
|
|
167
|
+
export function buildSignalLog(results) {
|
|
168
|
+
if (results.length === 0) {
|
|
169
|
+
return "No signals fired in the analysis window. Momentum threshold (1.5%) not crossed in recent candles.";
|
|
232
170
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const COOLDOWN_MS = 12 * 60 * 60 * 1000; // 12-hour cooldown between signals per market
|
|
251
|
-
for (let i = BACKTEST_WINDOW_HOURS; i < history.length; i++) {
|
|
252
|
-
const windowStart = history[i - BACKTEST_WINDOW_HOURS];
|
|
253
|
-
const current = history[i];
|
|
254
|
-
if (windowStart.p === 0)
|
|
255
|
-
continue;
|
|
256
|
-
const momentum = (current.p - windowStart.p) / windowStart.p;
|
|
257
|
-
if (Math.abs(momentum) < BACKTEST_MOMENTUM_THRESHOLD)
|
|
258
|
-
continue;
|
|
259
|
-
const tMs = current.t * 1000;
|
|
260
|
-
if (tMs - lastSignalAtMs < COOLDOWN_MS)
|
|
261
|
-
continue;
|
|
262
|
-
lastSignalAtMs = tMs;
|
|
263
|
-
signals.push({
|
|
264
|
-
firedAt: tMs,
|
|
265
|
-
oddsAtSignal: current.p,
|
|
266
|
-
direction: momentum > 0 ? "YES" : "NO",
|
|
267
|
-
momentum,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
return signals;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Kelly Criterion: f* = (p*b - q) / b
|
|
274
|
-
* where b = net odds (profit per $ risked), p = win probability, q = 1 - p
|
|
275
|
-
* Capped at 10% maximum.
|
|
276
|
-
*/
|
|
277
|
-
export function kellySize(odds, winProb) {
|
|
278
|
-
if (odds <= 0 || odds >= 1)
|
|
279
|
-
return 0;
|
|
280
|
-
const b = (1 - odds) / odds; // net odds
|
|
281
|
-
const q = 1 - winProb;
|
|
282
|
-
const kelly = (winProb * b - q) / b;
|
|
283
|
-
return Math.max(0, Math.min(0.1, kelly));
|
|
284
|
-
}
|
|
285
|
-
export function computePnl(decision, odds, resolution, kellySizePct) {
|
|
286
|
-
if (decision === "PASS" || decision === "ERROR")
|
|
287
|
-
return 0;
|
|
288
|
-
const betYes = decision === "BUY_YES";
|
|
289
|
-
const won = betYes ? resolution === 1 : resolution === 0;
|
|
290
|
-
const betOdds = betYes ? odds : 1 - odds;
|
|
291
|
-
if (won) {
|
|
292
|
-
// Profit per $ = (1 - betOdds) / betOdds
|
|
293
|
-
return kellySizePct * ((1 - betOdds) / betOdds);
|
|
171
|
+
const correlated = results.filter((r) => r.correlatedMoves.length > 0).length;
|
|
172
|
+
const lines = [
|
|
173
|
+
`Total signals: ${results.length}`,
|
|
174
|
+
`Correlated with Polymarket moves >2%: ${correlated}/${results.length}`,
|
|
175
|
+
`Correlation rate: ${((correlated / results.length) * 100).toFixed(1)}%`,
|
|
176
|
+
"",
|
|
177
|
+
"Signal Log:",
|
|
178
|
+
];
|
|
179
|
+
for (const r of results) {
|
|
180
|
+
const ts = new Date(r.signal.firedAt).toISOString();
|
|
181
|
+
const pct = (r.signal.momentum * 100).toFixed(2);
|
|
182
|
+
const corrStr = r.correlatedMoves.length > 0
|
|
183
|
+
? r.correlatedMoves
|
|
184
|
+
.map((m) => `${m.question.slice(0, 40)} (${(m.oddsChange * 100).toFixed(1)}% ${m.direction})`)
|
|
185
|
+
.join("; ")
|
|
186
|
+
: "no correlated moves";
|
|
187
|
+
lines.push(` [${ts}] ${r.signal.direction} ${pct}% @ $${r.signal.price.toFixed(0)} | conf=${r.signal.confidence.toFixed(2)} | ${corrStr}`);
|
|
294
188
|
}
|
|
295
|
-
return
|
|
189
|
+
return lines.join("\n");
|
|
296
190
|
}
|
|
297
191
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
192
|
+
* Spawn claude --print and ask for signal pattern analysis.
|
|
193
|
+
* Returns Claude's response text or a fallback message on failure.
|
|
300
194
|
*/
|
|
301
|
-
export async function askClaude(
|
|
302
|
-
const
|
|
303
|
-
|
|
195
|
+
export async function askClaude(signalLog) {
|
|
196
|
+
const prompt = `Given these signal firings and Polymarket odds movements, what patterns do you see? ` +
|
|
197
|
+
`Which signal types (high momentum, news-boosted, specific time windows) correlate best with market moves? ` +
|
|
198
|
+
`What threshold would maximize signal quality?\n\n${signalLog}`;
|
|
304
199
|
return new Promise((resolve) => {
|
|
305
200
|
const proc = spawn("claude", ["--print", "--model", "claude-haiku-4-5-20251001"], {
|
|
306
201
|
env: { ...process.env },
|
|
307
202
|
stdio: ["pipe", "pipe", "pipe"],
|
|
308
203
|
});
|
|
309
|
-
// Send prompt via stdin then close it so claude knows there is no more input
|
|
310
204
|
proc.stdin.write(prompt);
|
|
311
205
|
proc.stdin.end();
|
|
312
206
|
let stdout = "";
|
|
313
|
-
let stderr = "";
|
|
314
207
|
let timedOut = false;
|
|
315
208
|
proc.stdout.on("data", (chunk) => {
|
|
316
209
|
stdout += chunk.toString();
|
|
317
210
|
});
|
|
318
|
-
proc.stderr.on("data", (
|
|
319
|
-
stderr += chunk.toString();
|
|
320
|
-
});
|
|
211
|
+
proc.stderr.on("data", () => { }); // suppress stderr noise
|
|
321
212
|
const timer = setTimeout(() => {
|
|
322
213
|
timedOut = true;
|
|
323
214
|
proc.kill("SIGTERM");
|
|
324
|
-
},
|
|
215
|
+
}, 60_000);
|
|
325
216
|
proc.on("close", (code) => {
|
|
326
217
|
clearTimeout(timer);
|
|
327
|
-
const latencyMs = Date.now() - start;
|
|
328
218
|
if (timedOut || code !== 0) {
|
|
329
|
-
|
|
330
|
-
? "timeout after 30s"
|
|
331
|
-
: `exit code ${code}${stderr ? ": " + stderr.slice(0, 200) : ""}`;
|
|
332
|
-
log("warn", { source: "backtest", event: "claude_error", error: err });
|
|
333
|
-
resolve({ decision: "ERROR", latencyMs });
|
|
219
|
+
resolve("(Claude interpretation unavailable — subprocess error or timeout)");
|
|
334
220
|
return;
|
|
335
221
|
}
|
|
336
|
-
|
|
337
|
-
let decision = "PASS";
|
|
338
|
-
if (text.includes("BUY_YES"))
|
|
339
|
-
decision = "BUY_YES";
|
|
340
|
-
else if (text.includes("BUY_NO"))
|
|
341
|
-
decision = "BUY_NO";
|
|
342
|
-
log("info", {
|
|
343
|
-
source: "backtest",
|
|
344
|
-
event: "claude_decision",
|
|
345
|
-
question: question.slice(0, 60),
|
|
346
|
-
decision,
|
|
347
|
-
latencyMs,
|
|
348
|
-
});
|
|
349
|
-
resolve({ decision, latencyMs });
|
|
222
|
+
resolve(stdout.trim() || "(No interpretation returned)");
|
|
350
223
|
});
|
|
351
|
-
proc.on("error", (
|
|
224
|
+
proc.on("error", () => {
|
|
352
225
|
clearTimeout(timer);
|
|
353
|
-
|
|
354
|
-
log("warn", { source: "backtest", event: "claude_error", error: String(err) });
|
|
355
|
-
resolve({ decision: "ERROR", latencyMs });
|
|
226
|
+
resolve("(Claude interpretation unavailable — spawn error)");
|
|
356
227
|
});
|
|
357
228
|
});
|
|
358
229
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
claudeErrors,
|
|
376
|
-
avgLatencyMs,
|
|
377
|
-
maxLatencyMs,
|
|
378
|
-
buyYesTotal: buyYes.length,
|
|
379
|
-
buyYesCorrect: buyYes.filter((r) => r.correct).length,
|
|
380
|
-
buyNoTotal: buyNo.length,
|
|
381
|
-
buyNoCorrect: buyNo.filter((r) => r.correct).length,
|
|
382
|
-
passCount: passes.length,
|
|
383
|
-
avgKellyPct,
|
|
384
|
-
totalPnl,
|
|
385
|
-
results,
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
export function formatReport(report, date) {
|
|
389
|
-
const totalDecisions = report.buyYesTotal + report.buyNoTotal;
|
|
390
|
-
const totalCorrect = report.buyYesCorrect + report.buyNoCorrect;
|
|
391
|
-
const winRate = totalDecisions > 0 ? (totalCorrect / totalDecisions) * 100 : 0;
|
|
392
|
-
const signalRate = report.marketsAnalyzed > 0
|
|
393
|
-
? (report.signalsFired / report.marketsAnalyzed) * 100
|
|
394
|
-
: 0;
|
|
395
|
-
const yesAcc = report.buyYesTotal > 0
|
|
396
|
-
? `${report.buyYesCorrect}/${report.buyYesTotal} (${((report.buyYesCorrect / report.buyYesTotal) * 100).toFixed(1)}%)`
|
|
397
|
-
: "0/0 (n/a)";
|
|
398
|
-
const noAcc = report.buyNoTotal > 0
|
|
399
|
-
? `${report.buyNoCorrect}/${report.buyNoTotal} (${((report.buyNoCorrect / report.buyNoTotal) * 100).toFixed(1)}%)`
|
|
400
|
-
: "0/0 (n/a)";
|
|
401
|
-
const claudeStatus = report.claudeErrors === 0
|
|
402
|
-
? ` ✓ All ${report.claudeSuccesses} calls succeeded`
|
|
403
|
-
: ` ✓ ${report.claudeSuccesses} calls succeeded\n ✗ ${report.claudeErrors} error${report.claudeErrors !== 1 ? "s" : ""}`;
|
|
404
|
-
let verdict;
|
|
405
|
-
if (totalDecisions === 0) {
|
|
406
|
-
verdict =
|
|
407
|
-
"INSUFFICIENT DATA: No actionable signals. Either no price history from API, " +
|
|
408
|
-
"signals never crossed the 5% threshold, or all signals fired after market resolution.";
|
|
409
|
-
}
|
|
410
|
-
else if (totalDecisions < 5) {
|
|
411
|
-
verdict =
|
|
412
|
-
`TOO FEW TRADES: Only ${totalDecisions} trade${totalDecisions !== 1 ? "s" : ""} — ` +
|
|
413
|
-
"cannot distinguish edge from luck. Need 30+ trades for statistical significance.";
|
|
414
|
-
}
|
|
415
|
-
else if (winRate > 60) {
|
|
416
|
-
verdict =
|
|
417
|
-
`POSSIBLE EDGE: Win rate ${winRate.toFixed(1)}% exceeds 50% baseline. ` +
|
|
418
|
-
`P&L: ${report.totalPnl >= 0 ? "+" : ""}${(report.totalPnl * 100).toFixed(1)}% of bankroll. ` +
|
|
419
|
-
"Needs larger sample (30+ trades) to confirm.";
|
|
420
|
-
}
|
|
421
|
-
else if (winRate > 50) {
|
|
422
|
-
verdict =
|
|
423
|
-
`WEAK SIGNAL: Win rate ${winRate.toFixed(1)}% slightly above baseline. ` +
|
|
424
|
-
"Cannot yet distinguish from noise. More data needed.";
|
|
425
|
-
}
|
|
426
|
-
else {
|
|
427
|
-
verdict =
|
|
428
|
-
`NO EDGE DETECTED: Win rate ${winRate.toFixed(1)}% at or below 50% baseline. ` +
|
|
429
|
-
"Current signal parameters not predictive on this historical data.";
|
|
430
|
-
}
|
|
431
|
-
const lines = [
|
|
432
|
-
"=== POLYMARKET-ARB BACKTEST REPORT ===",
|
|
433
|
-
`Date: ${date}`,
|
|
434
|
-
"",
|
|
435
|
-
`Markets analyzed: ${report.marketsAnalyzed}`,
|
|
436
|
-
`Signals fired: ${report.signalsFired} (${signalRate.toFixed(1)}% of markets)`,
|
|
437
|
-
`Claude Code: ${report.claudeSuccesses}/${report.signalsFired} decisions returned (${report.claudeErrors} error${report.claudeErrors !== 1 ? "s" : ""})`,
|
|
438
|
-
`Claude latency: avg ${(report.avgLatencyMs / 1000).toFixed(1)}s, max ${(report.maxLatencyMs / 1000).toFixed(1)}s`,
|
|
230
|
+
/**
|
|
231
|
+
* Render the full backtest report as Markdown.
|
|
232
|
+
*/
|
|
233
|
+
export function generateMarkdownReport(report) {
|
|
234
|
+
const signalRows = report.signals.length > 0
|
|
235
|
+
? report.signals.map((r) => {
|
|
236
|
+
const ts = new Date(r.signal.firedAt).toISOString().replace("T", " ").slice(0, 19);
|
|
237
|
+
const mom = `${(r.signal.momentum * 100).toFixed(2)}%`;
|
|
238
|
+
const marketMove = r.correlatedMoves.length > 0
|
|
239
|
+
? r.correlatedMoves.map((m) => `${(m.oddsChange * 100).toFixed(1)}%`).join(", ")
|
|
240
|
+
: "—";
|
|
241
|
+
return `| ${ts} | ${r.signal.symbol} | ${mom} | ${r.signal.direction} | ${marketMove} |`;
|
|
242
|
+
})
|
|
243
|
+
: ["| — | — | — | — | — |"];
|
|
244
|
+
return [
|
|
245
|
+
`# Polymarket Backtest — ${report.date}`,
|
|
439
246
|
"",
|
|
440
|
-
"
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
247
|
+
"## Summary",
|
|
248
|
+
`- Candles analyzed: ${report.candlesAnalyzed}`,
|
|
249
|
+
`- Signals fired: ${report.signalsFired}`,
|
|
250
|
+
`- Signal rate: ${report.signalRatePerDay.toFixed(1)} per day`,
|
|
251
|
+
`- Markets checked per signal: ${report.marketsChecked}`,
|
|
252
|
+
`- Correlated moves (signal + market move >2%): ${report.correlatedSignals}`,
|
|
253
|
+
`- Correlation rate: ${report.correlationRate.toFixed(1)}%`,
|
|
444
254
|
"",
|
|
445
|
-
"
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
255
|
+
"## Signal Log",
|
|
256
|
+
"| Time | Symbol | Momentum | Direction | Market Move |",
|
|
257
|
+
"|------|--------|----------|-----------|-------------|",
|
|
258
|
+
...signalRows,
|
|
449
259
|
"",
|
|
450
|
-
"
|
|
451
|
-
|
|
260
|
+
"## Interpretation",
|
|
261
|
+
report.claudeInterpretation,
|
|
452
262
|
"",
|
|
453
|
-
|
|
454
|
-
];
|
|
455
|
-
return lines.join("\n");
|
|
263
|
+
].join("\n");
|
|
456
264
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Write a report to disk. Creates `dir` if it doesn't exist.
|
|
267
|
+
* Returns the path written.
|
|
268
|
+
*/
|
|
269
|
+
export function writeReport(text, date, dir = "research") {
|
|
270
|
+
if (!fs.existsSync(dir)) {
|
|
271
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
272
|
+
}
|
|
273
|
+
const reportPath = path.join(dir, `backtest-results-${date}.md`);
|
|
274
|
+
fs.writeFileSync(reportPath, text);
|
|
460
275
|
return reportPath;
|
|
461
276
|
}
|
|
462
277
|
//# sourceMappingURL=backtest.js.map
|
package/dist/backtest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backtest.js","sourceRoot":"","sources":["../src/backtest.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backtest.js","sourceRoot":"","sources":["../src/backtest.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backtestRunner.d.ts","sourceRoot":"","sources":["../src/backtestRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"backtestRunner.d.ts","sourceRoot":"","sources":["../src/backtestRunner.ts"],"names":[],"mappings":"AAoBA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAiFjD"}
|
package/dist/backtestRunner.js
CHANGED
|
@@ -1,167 +1,74 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const
|
|
1
|
+
import { fetchCoinbaseCandles, replaySignals, fetchPolymarketMarkets, fetchMarketTrades, findCorrelatedMoves, askClaude, buildSignalLog, generateMarkdownReport, writeReport, } from "./backtest.js";
|
|
2
|
+
const PRODUCT = "BTC-USD";
|
|
3
|
+
const GRANULARITY = 60; // 1-minute candles
|
|
4
|
+
const CANDLE_LIMIT = 300; // ~5 hours of data
|
|
5
|
+
const POLYMARKET_MARKETS = 20;
|
|
6
6
|
export async function runBacktest() {
|
|
7
7
|
const date = new Date().toISOString().slice(0, 10);
|
|
8
8
|
console.log("=== POLYMARKET-ARB BACKTESTING HARNESS ===");
|
|
9
|
-
console.log(`Fetching
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
console.error("ERROR: No resolved markets found.\n" +
|
|
9
|
+
console.log(`Fetching ${CANDLE_LIMIT} × ${GRANULARITY}s candles for ${PRODUCT}...`);
|
|
10
|
+
const candles = await fetchCoinbaseCandles(PRODUCT, GRANULARITY, CANDLE_LIMIT);
|
|
11
|
+
if (candles.length === 0) {
|
|
12
|
+
console.error("ERROR: No candles returned from Coinbase REST API.\n" +
|
|
14
13
|
"Possible causes:\n" +
|
|
15
|
-
" •
|
|
16
|
-
" •
|
|
17
|
-
" • outcomePrices not cleanly 0 or 1 (market still settling)");
|
|
14
|
+
" • API rate-limited or unreachable\n" +
|
|
15
|
+
" • Network error");
|
|
18
16
|
process.exit(1);
|
|
19
17
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
console.log(`Fetched ${candles.length} candles`);
|
|
19
|
+
const signals = replaySignals(candles, PRODUCT);
|
|
20
|
+
console.log(`Signals fired: ${signals.length} (threshold: 1.5% per candle)`);
|
|
21
|
+
console.log(`\nFetching ${POLYMARKET_MARKETS} active Polymarket markets...`);
|
|
22
|
+
const markets = await fetchPolymarketMarkets(POLYMARKET_MARKETS);
|
|
23
|
+
console.log(`Fetched ${markets.length} qualifying markets (volume > $10k)`);
|
|
24
|
+
// Pre-fetch trades for all markets once, then reuse across signals
|
|
25
|
+
const tradesByMarket = {};
|
|
26
|
+
if (signals.length > 0 && markets.length > 0) {
|
|
27
|
+
console.log(`Pre-fetching trades for ${markets.length} markets...`);
|
|
28
|
+
for (let i = 0; i < markets.length; i++) {
|
|
29
|
+
const market = markets[i];
|
|
30
|
+
if (market.clobTokenId) {
|
|
31
|
+
process.stdout.write(`\r [${i + 1}/${markets.length}] ${market.question.slice(0, 50)}`);
|
|
32
|
+
tradesByMarket[market.id] = await fetchMarketTrades(market.clobTokenId);
|
|
33
|
+
}
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
const signals = replaySignals(history).slice(0, MAX_SIGNALS_PER_MARKET);
|
|
36
|
-
if (signals.length === 0) {
|
|
37
|
-
marketsNoSignal++;
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
for (const signal of signals) {
|
|
41
|
-
// Skip signals that fired at or after resolution — unfair look-ahead
|
|
42
|
-
if (signal.firedAt >= market.resolutionTime)
|
|
43
|
-
continue;
|
|
44
|
-
const { decision, latencyMs } = await askClaude(market.question, signal.oddsAtSignal);
|
|
45
|
-
const betOdds = decision === "BUY_YES" ? signal.oddsAtSignal : 1 - signal.oddsAtSignal;
|
|
46
|
-
// Assume modest 65% win probability as prior when signal fires
|
|
47
|
-
const WIN_PROB_PRIOR = 0.65;
|
|
48
|
-
const kellySizePct = decision !== "PASS" && decision !== "ERROR"
|
|
49
|
-
? kellySize(betOdds, WIN_PROB_PRIOR)
|
|
50
|
-
: 0;
|
|
51
|
-
const pnl = computePnl(decision, signal.oddsAtSignal, market.resolution, kellySizePct);
|
|
52
|
-
const correct = decision === "BUY_YES"
|
|
53
|
-
? market.resolution === 1
|
|
54
|
-
: decision === "BUY_NO"
|
|
55
|
-
? market.resolution === 0
|
|
56
|
-
: false;
|
|
57
|
-
results.push({
|
|
58
|
-
marketId: market.id,
|
|
59
|
-
question: market.question,
|
|
60
|
-
signalFiredAt: signal.firedAt,
|
|
61
|
-
oddsAtSignal: signal.oddsAtSignal,
|
|
62
|
-
claudeDecision: decision,
|
|
63
|
-
claudeLatencyMs: latencyMs,
|
|
64
|
-
actualResolution: market.resolution,
|
|
65
|
-
correct,
|
|
66
|
-
kellySizePct,
|
|
67
|
-
hypotheticalPnl: pnl,
|
|
68
|
-
});
|
|
69
|
-
log("info", {
|
|
70
|
-
source: "backtest",
|
|
71
|
-
event: "result",
|
|
72
|
-
question: market.question.slice(0, 60),
|
|
73
|
-
decision,
|
|
74
|
-
oddsAtSignal: signal.oddsAtSignal.toFixed(3),
|
|
75
|
-
resolution: market.resolution,
|
|
76
|
-
correct,
|
|
77
|
-
pnl: pnl.toFixed(4),
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
process.stdout.write("\n\n");
|
|
82
|
-
console.log(`Price history: ${marketsWithHistory}/${markets.length} markets had history, ` +
|
|
83
|
-
`${marketsNoHistory} had no/insufficient data, ` +
|
|
84
|
-
`${marketsNoSignal} had history but no signal fired`);
|
|
85
|
-
// ── Active markets probe ──────────────────────────────────────────────────
|
|
86
|
-
let activeProbeResults = [];
|
|
87
|
-
if (marketsWithHistory === 0) {
|
|
88
|
-
console.log("\nFetching active markets for live signal probe...");
|
|
89
|
-
const activeMarkets = await fetchActiveMarkets(20);
|
|
90
|
-
let activeWithHistory = 0;
|
|
91
|
-
let activeSignalsFound = 0;
|
|
92
|
-
for (const market of activeMarkets) {
|
|
93
|
-
const tokenId = market.clobTokenId || market.conditionId;
|
|
94
|
-
const history = await fetchPriceHistory(tokenId);
|
|
95
|
-
if (history.length < 5)
|
|
96
|
-
continue;
|
|
97
|
-
activeWithHistory++;
|
|
98
|
-
const signals = replaySignals(history);
|
|
99
|
-
if (signals.length === 0)
|
|
100
|
-
continue;
|
|
101
|
-
activeSignalsFound++;
|
|
102
|
-
const signal = signals[0];
|
|
103
|
-
const { decision, latencyMs } = await askClaude(market.question, signal.oddsAtSignal);
|
|
104
|
-
activeProbeResults.push({
|
|
105
|
-
question: market.question,
|
|
106
|
-
oddsAtSignal: signal.oddsAtSignal,
|
|
107
|
-
decision,
|
|
108
|
-
latencyMs,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
console.log(`Active market probe: ${activeMarkets.length} markets, ` +
|
|
112
|
-
`${activeWithHistory} had price history, ` +
|
|
113
|
-
`${activeSignalsFound} signals found`);
|
|
35
|
+
process.stdout.write("\n");
|
|
114
36
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
37
|
+
const results = signals.map((signal) => {
|
|
38
|
+
const correlatedMoves = findCorrelatedMoves(signal, markets, tradesByMarket);
|
|
39
|
+
return {
|
|
40
|
+
signal,
|
|
41
|
+
marketsChecked: markets.length,
|
|
42
|
+
correlatedMoves,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
const correlatedCount = results.filter((r) => r.correlatedMoves.length > 0).length;
|
|
46
|
+
const candleMinutes = (candles.length * GRANULARITY) / 60;
|
|
47
|
+
const signalRatePerDay = candleMinutes > 0 ? (signals.length / candleMinutes) * 24 * 60 : 0;
|
|
48
|
+
console.log(`\nResults:`);
|
|
49
|
+
console.log(` Signals fired: ${signals.length}`);
|
|
50
|
+
console.log(` Signals with correlated Polymarket moves: ${correlatedCount}/${signals.length}`);
|
|
51
|
+
console.log(` Correlation rate: ${signals.length > 0 ? ((correlatedCount / signals.length) * 100).toFixed(1) : "0.0"}%`);
|
|
52
|
+
const signalLog = buildSignalLog(results);
|
|
53
|
+
console.log("\nAsking Claude for interpretation...");
|
|
54
|
+
const claudeInterpretation = await askClaude(signalLog);
|
|
55
|
+
console.log("Claude responded.");
|
|
56
|
+
const report = {
|
|
57
|
+
date,
|
|
58
|
+
product: PRODUCT,
|
|
59
|
+
candlesAnalyzed: candles.length,
|
|
60
|
+
signalsFired: signals.length,
|
|
61
|
+
signalRatePerDay,
|
|
62
|
+
marketsChecked: markets.length,
|
|
63
|
+
correlatedSignals: correlatedCount,
|
|
64
|
+
correlationRate: signals.length > 0 ? (correlatedCount / signals.length) * 100 : 0,
|
|
65
|
+
signals: results,
|
|
66
|
+
claudeInterpretation,
|
|
67
|
+
};
|
|
68
|
+
const reportText = generateMarkdownReport(report);
|
|
126
69
|
const reportPath = writeReport(reportText, date);
|
|
127
70
|
console.log(`\nReport written to: ${reportPath}`);
|
|
128
|
-
|
|
129
|
-
console.warn(`\nWARNING: ${probe.errors} Claude call(s) failed.\n` +
|
|
130
|
-
"Check that CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_AUTH_TOKEN is set.");
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
function buildFullReport(report, probe, marketsNoHistory, marketsTotal, date, activeProbeResults = []) {
|
|
134
|
-
let text = formatBaseReport(report, date);
|
|
135
|
-
if (marketsNoHistory === marketsTotal) {
|
|
136
|
-
text +=
|
|
137
|
-
"\n\nAPI FINDING: CLOB /prices-history endpoint returned empty data for all " +
|
|
138
|
-
marketsTotal +
|
|
139
|
-
" resolved markets.\n" +
|
|
140
|
-
"Investigation results:\n" +
|
|
141
|
-
" • GET /prices-history returns {history:[]} for all closed/resolved markets\n" +
|
|
142
|
-
" • Active markets: price history exists but only ~2 data points (insufficient for 4h window)\n" +
|
|
143
|
-
" • The end_date_min filter works to find recent markets efficiently\n" +
|
|
144
|
-
" • Recommendation: use a dedicated historical data provider (Dune Analytics, TheGraph) for future backtests\n";
|
|
145
|
-
}
|
|
146
|
-
text +=
|
|
147
|
-
"\n\nCLAUDE INTEGRATION PROBE (5 markets, no momentum signal required):\n" +
|
|
148
|
-
` ${probe.success}/5 calls succeeded (${probe.errors} errors)\n` +
|
|
149
|
-
` Avg latency: ${(probe.avgLatencyMs / 1000).toFixed(1)}s\n`;
|
|
150
|
-
for (const r of probe.sample) {
|
|
151
|
-
const icon = r.claudeDecision === "ERROR" ? "✗" : "✓";
|
|
152
|
-
text +=
|
|
153
|
-
` ${icon} "${r.question.slice(0, 50)}" → ${r.claudeDecision} ` +
|
|
154
|
-
`(${(r.claudeLatencyMs / 1000).toFixed(1)}s, resolved: ${r.actualResolution === 1 ? "YES" : "NO"})\n`;
|
|
155
|
-
}
|
|
156
|
-
if (activeProbeResults.length > 0) {
|
|
157
|
-
text += "\n\nACTIVE MARKET PROBE RESULTS:\n";
|
|
158
|
-
for (const r of activeProbeResults) {
|
|
159
|
-
text +=
|
|
160
|
-
` "${r.question.slice(0, 50)}" → ${r.decision} ` +
|
|
161
|
-
`(odds: ${(r.oddsAtSignal * 100).toFixed(1)}%, ${(r.latencyMs / 1000).toFixed(1)}s)\n`;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return text;
|
|
71
|
+
console.log("\n" + reportText);
|
|
165
72
|
}
|
|
166
73
|
// Run when invoked directly (not imported)
|
|
167
74
|
const selfPath = process.argv[1] ?? "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backtestRunner.js","sourceRoot":"","sources":["../src/backtestRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,
|
|
1
|
+
{"version":3,"file":"backtestRunner.js","sourceRoot":"","sources":["../src/backtestRunner.ts"],"names":[],"mappings":"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"}
|