polly-gamba 1.0.13 → 1.0.14

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/index.js CHANGED
@@ -88,6 +88,7 @@ async function main() {
88
88
  const signals = new coinbase_ws_1.CoinbaseSignalDetector();
89
89
  const monitor = new position_monitor_1.PositionMonitor(process.env.REDIS_URL || 'redis://localhost:6379', 'polly');
90
90
  monitor.setTrader(anthropicTrader);
91
+ monitor.start();
91
92
  anthropicTrader.start();
92
93
  ollamaTrader.start();
93
94
  expiringTrader.start();
@@ -99,13 +100,8 @@ async function main() {
99
100
  });
100
101
  signals.start();
101
102
  console.log('[polly-gamba] Listening for BTC/ETH price signals (threshold: 0.5% in 60s)...');
102
- // Position monitor: check every 15 minutes for exits
103
- const SCAN_INTERVAL_MS = 15 * 60 * 1000; // 15 minutes
104
- monitor.checkPositions().catch((e) => console.error('[monitor]', e.message));
105
- setInterval(() => {
106
- monitor.checkPositions().catch((e) => console.error('[monitor]', e.message));
107
- }, SCAN_INTERVAL_MS);
108
103
  // Autonomous scan on startup and every 15 minutes
104
+ const SCAN_INTERVAL_MS = 15 * 60 * 1000; // 15 minutes
109
105
  autonomousScan(anthropicTrader, ollamaTrader).catch((e) => {
110
106
  console.error('[error] autonomous scan failed:', e.message);
111
107
  });
@@ -348,6 +348,8 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (req) => {
348
348
  throw new Error(`Unknown tool: ${name}`);
349
349
  });
350
350
  async function main() {
351
+ // Initialize budget key (NX = don't overwrite if already set)
352
+ await redis.set(`${REDIS_PREFIX}:budget`, '500', 'NX');
351
353
  const transport = new stdio_js_1.StdioServerTransport();
352
354
  await server.connect(transport);
353
355
  console.error('[mcp] polly-gamba-paper MCP server started (stdio)');
@@ -18,7 +18,10 @@ export declare class PositionMonitor {
18
18
  private prefix;
19
19
  private trader;
20
20
  setTrader(trader: ClaudeTrader): void;
21
- constructor(redisUrl: string, prefix: string);
21
+ private intervalMs;
22
+ private intervalHandle;
23
+ constructor(redisUrl: string, prefix: string, intervalMs?: number);
24
+ start(): void;
22
25
  checkPositions(): Promise<void>;
23
26
  private fetchCurrentPrice;
24
27
  stop(): void;
@@ -12,7 +12,9 @@ class PositionMonitor {
12
12
  setTrader(trader) {
13
13
  this.trader = trader;
14
14
  }
15
- constructor(redisUrl, prefix) {
15
+ intervalMs;
16
+ intervalHandle = null;
17
+ constructor(redisUrl, prefix, intervalMs = 15 * 60 * 1000) {
16
18
  this.redis = new ioredis_1.default(redisUrl, {
17
19
  retryStrategy: (times) => Math.min(times * 500, 5000),
18
20
  maxRetriesPerRequest: null,
@@ -20,6 +22,13 @@ class PositionMonitor {
20
22
  });
21
23
  this.redis.on('error', (e) => console.error('[position-monitor:redis]', e.message));
22
24
  this.prefix = prefix;
25
+ this.intervalMs = intervalMs;
26
+ }
27
+ start() {
28
+ this.checkPositions().catch((e) => console.error('[monitor]', e.message));
29
+ this.intervalHandle = setInterval(() => {
30
+ this.checkPositions().catch((e) => console.error('[monitor]', e.message));
31
+ }, this.intervalMs);
23
32
  }
24
33
  async checkPositions() {
25
34
  const raw = await this.redis.lrange(`${this.prefix}:positions`, 0, -1);
@@ -42,17 +51,20 @@ class PositionMonitor {
42
51
  console.log(`[position-monitor] 0 open positions to check`);
43
52
  return;
44
53
  }
45
- // Deduplicate market fetches
54
+ // Deduplicate market fetches keyed by marketId_outcome
46
55
  const marketPriceCache = new Map();
47
- const uniqueMarkets = [...new Set(toCheck.map(p => p.market_id))];
48
- await Promise.all(uniqueMarkets.map(async (marketId) => {
49
- const result = await this.fetchCurrentPrice(marketId, 'Yes').catch(() => null);
50
- marketPriceCache.set(marketId, result);
56
+ const uniqueKeys = [...new Set(toCheck.map(p => `${p.market_id}|${p.outcome}`))];
57
+ await Promise.all(uniqueKeys.map(async (key) => {
58
+ const sep = key.indexOf('|');
59
+ const marketId = key.slice(0, sep);
60
+ const outcome = key.slice(sep + 1);
61
+ const result = await this.fetchCurrentPrice(marketId, outcome).catch(() => null);
62
+ marketPriceCache.set(key, result);
51
63
  }));
52
64
  // Build review candidates with current price data for Claude
53
65
  const reviewCandidates = [];
54
66
  for (const pos of toCheck) {
55
- const currentPrice = await this.fetchCurrentPrice(pos.market_id, pos.outcome);
67
+ const currentPrice = marketPriceCache.get(`${pos.market_id}|${pos.outcome}`) ?? null;
56
68
  if (!currentPrice)
57
69
  continue;
58
70
  const entryPrice = pos.price;
@@ -108,6 +120,10 @@ class PositionMonitor {
108
120
  }
109
121
  }
110
122
  stop() {
123
+ if (this.intervalHandle) {
124
+ clearInterval(this.intervalHandle);
125
+ this.intervalHandle = null;
126
+ }
111
127
  this.redis.disconnect();
112
128
  }
113
129
  }
package/package.json CHANGED
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "name": "polly-gamba",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Coinbase price signal → Claude brain → Polymarket CLOB execution",
5
5
  "main": "dist/index.js",
6
- "bin": {
7
- "polly-gamba": "dist/index.js"
8
- },
9
6
  "scripts": {
10
7
  "start": "ts-node src/index.ts",
11
8
  "mcp": "ts-node src/mcp/server.ts",
package/src/index.ts CHANGED
@@ -65,6 +65,7 @@ async function main(): Promise<void> {
65
65
  )
66
66
 
67
67
  monitor.setTrader(anthropicTrader)
68
+ monitor.start()
68
69
 
69
70
  anthropicTrader.start()
70
71
  ollamaTrader.start()
@@ -80,14 +81,8 @@ async function main(): Promise<void> {
80
81
  signals.start()
81
82
  console.log('[polly-gamba] Listening for BTC/ETH price signals (threshold: 0.5% in 60s)...')
82
83
 
83
- // Position monitor: check every 15 minutes for exits
84
- const SCAN_INTERVAL_MS = 15 * 60 * 1000 // 15 minutes
85
- monitor.checkPositions().catch((e: Error) => console.error('[monitor]', e.message))
86
- setInterval(() => {
87
- monitor.checkPositions().catch((e: Error) => console.error('[monitor]', e.message))
88
- }, SCAN_INTERVAL_MS)
89
-
90
84
  // Autonomous scan on startup and every 15 minutes
85
+ const SCAN_INTERVAL_MS = 15 * 60 * 1000 // 15 minutes
91
86
  autonomousScan(anthropicTrader, ollamaTrader).catch((e: Error) => {
92
87
  console.error('[error] autonomous scan failed:', e.message)
93
88
  })
package/src/mcp-server.ts CHANGED
@@ -348,6 +348,8 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
348
348
  })
349
349
 
350
350
  async function main() {
351
+ // Initialize budget key (NX = don't overwrite if already set)
352
+ await redis.set(`${REDIS_PREFIX}:budget`, '500', 'NX')
351
353
  const transport = new StdioServerTransport()
352
354
  await server.connect(transport)
353
355
  console.error('[mcp] polly-gamba-paper MCP server started (stdio)')
@@ -30,7 +30,10 @@ export class PositionMonitor {
30
30
  this.trader = trader
31
31
  }
32
32
 
33
- constructor(redisUrl: string, prefix: string) {
33
+ private intervalMs: number
34
+ private intervalHandle: NodeJS.Timeout | null = null
35
+
36
+ constructor(redisUrl: string, prefix: string, intervalMs = 15 * 60 * 1000) {
34
37
  this.redis = new Redis(redisUrl, {
35
38
  retryStrategy: (times) => Math.min(times * 500, 5000),
36
39
  maxRetriesPerRequest: null,
@@ -38,6 +41,14 @@ export class PositionMonitor {
38
41
  })
39
42
  this.redis.on('error', (e) => console.error('[position-monitor:redis]', e.message))
40
43
  this.prefix = prefix
44
+ this.intervalMs = intervalMs
45
+ }
46
+
47
+ start(): void {
48
+ this.checkPositions().catch((e: Error) => console.error('[monitor]', e.message))
49
+ this.intervalHandle = setInterval(() => {
50
+ this.checkPositions().catch((e: Error) => console.error('[monitor]', e.message))
51
+ }, this.intervalMs)
41
52
  }
42
53
 
43
54
  async checkPositions(): Promise<void> {
@@ -61,12 +72,15 @@ export class PositionMonitor {
61
72
  return
62
73
  }
63
74
 
64
- // Deduplicate market fetches
75
+ // Deduplicate market fetches keyed by marketId_outcome
65
76
  const marketPriceCache = new Map<string, MarketPrice | null>()
66
- const uniqueMarkets = [...new Set(toCheck.map(p => p.market_id))]
67
- await Promise.all(uniqueMarkets.map(async (marketId) => {
68
- const result = await this.fetchCurrentPrice(marketId, 'Yes').catch(() => null)
69
- marketPriceCache.set(marketId, result)
77
+ const uniqueKeys = [...new Set(toCheck.map(p => `${p.market_id}|${p.outcome}`))]
78
+ await Promise.all(uniqueKeys.map(async (key) => {
79
+ const sep = key.indexOf('|')
80
+ const marketId = key.slice(0, sep)
81
+ const outcome = key.slice(sep + 1)
82
+ const result = await this.fetchCurrentPrice(marketId, outcome).catch(() => null)
83
+ marketPriceCache.set(key, result)
70
84
  }))
71
85
 
72
86
  // Build review candidates with current price data for Claude
@@ -83,7 +97,7 @@ export class PositionMonitor {
83
97
  }> = []
84
98
 
85
99
  for (const pos of toCheck) {
86
- const currentPrice = await this.fetchCurrentPrice(pos.market_id, pos.outcome)
100
+ const currentPrice = marketPriceCache.get(`${pos.market_id}|${pos.outcome}`) ?? null
87
101
  if (!currentPrice) continue
88
102
 
89
103
  const entryPrice = pos.price
@@ -146,6 +160,10 @@ export class PositionMonitor {
146
160
  }
147
161
 
148
162
  stop(): void {
163
+ if (this.intervalHandle) {
164
+ clearInterval(this.intervalHandle)
165
+ this.intervalHandle = null
166
+ }
149
167
  this.redis.disconnect()
150
168
  }
151
169
  }
@@ -1,14 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "polly-paper": {
4
- "command": "npx",
5
- "args": ["ts-node", "/Users/feral/polly-gamba/src/mcp-server.ts"],
6
- "env": {
7
- "REDIS_URL": "redis://localhost:6379"
8
- }
9
- }
10
- },
11
- "permissions": {
12
- "allow": ["mcp__polly-paper__place_order", "mcp__polly-paper__skip_market"]
13
- }
14
- }
package/.mcp.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "polly-paper": {
4
- "command": "node",
5
- "args": ["/Users/feral/polly-gamba/dist/mcp-server.js"],
6
- "env": {
7
- "REDIS_URL": "redis://localhost:6379"
8
- }
9
- }
10
- }
11
- }