perp-cli 0.7.16 → 0.7.17
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.
|
@@ -86,10 +86,51 @@ export class FundingArbStrategy {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
// ── Same-exchange spot-perp hedges (e.g. PURR spot + PURR-PERP short on HL) ──
|
|
90
|
+
for (const [name, a] of adapters) {
|
|
91
|
+
try {
|
|
92
|
+
const spotState = await a._getSpotClearinghouseState?.();
|
|
93
|
+
if (!spotState?.balances)
|
|
94
|
+
continue;
|
|
95
|
+
const spotBalances = spotState.balances
|
|
96
|
+
.filter(b => Number(b.total) > 0 && b.coin.toUpperCase() !== "USDC");
|
|
97
|
+
const perpPositions = positionsByExchange.get(name) ?? [];
|
|
98
|
+
for (const perp of perpPositions) {
|
|
99
|
+
const perpKey = `${name}:${perp.symbol}`;
|
|
100
|
+
if (used.has(perpKey))
|
|
101
|
+
continue;
|
|
102
|
+
const base = perp.symbol.replace(/-PERP$/, "").toUpperCase();
|
|
103
|
+
const spotBal = spotBalances.find(b => b.coin.toUpperCase() === base);
|
|
104
|
+
if (spotBal && perp.side === "short") {
|
|
105
|
+
recovered.push({ symbol: base, longExchange: `${name}-spot`, shortExchange: name, entrySpread: 0, size: perp.size });
|
|
106
|
+
used.add(perpKey);
|
|
107
|
+
ctx.log(` [ARB] Detected spot-perp hedge: ${base} ${name}-spot↔${name}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch { /* adapter doesn't support spot */ }
|
|
112
|
+
}
|
|
89
113
|
if (recovered.length > 0) {
|
|
90
114
|
ctx.state.set("arbOpenPositions", recovered);
|
|
91
115
|
ctx.state.set("arbPositions", recovered.length);
|
|
92
|
-
ctx.log(` [ARB] Recovered ${recovered.length}
|
|
116
|
+
ctx.log(` [ARB] Recovered ${recovered.length} position(s): ${recovered.map(p => `${p.symbol} ${p.longExchange}↔${p.shortExchange}`).join(", ")}`);
|
|
117
|
+
}
|
|
118
|
+
// ── Load historical funding income ──
|
|
119
|
+
let historicalFunding = 0;
|
|
120
|
+
for (const [name, a] of adapters) {
|
|
121
|
+
try {
|
|
122
|
+
const payments = await a.getFundingPayments(200);
|
|
123
|
+
const sum = payments.reduce((s, p) => s + parseFloat(p.payment), 0);
|
|
124
|
+
if (Math.abs(sum) > 0.001) {
|
|
125
|
+
historicalFunding += sum;
|
|
126
|
+
ctx.log(` [FUND] ${name}: $${sum.toFixed(4)} historical funding`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch { /* not all adapters support this */ }
|
|
130
|
+
}
|
|
131
|
+
if (Math.abs(historicalFunding) > 0.001) {
|
|
132
|
+
ctx.state.set("fundingIncome", historicalFunding);
|
|
133
|
+
ctx.log(` [FUND] Total historical funding: $${historicalFunding.toFixed(4)}`);
|
|
93
134
|
}
|
|
94
135
|
}
|
|
95
136
|
catch (err) {
|
|
@@ -131,8 +172,8 @@ export class FundingArbStrategy {
|
|
|
131
172
|
try {
|
|
132
173
|
const payments = await a.getFundingPayments(50);
|
|
133
174
|
const startTime = ctx.state.get("fundingLastCheck");
|
|
134
|
-
const recent = payments.filter(p => p.
|
|
135
|
-
const sum = recent.reduce((s, p) => s + parseFloat(p.
|
|
175
|
+
const recent = payments.filter(p => p.time > startTime - 5 * 60 * 1000);
|
|
176
|
+
const sum = recent.reduce((s, p) => s + parseFloat(p.payment), 0);
|
|
136
177
|
totalFunding += sum;
|
|
137
178
|
if (Math.abs(sum) > 0.001) {
|
|
138
179
|
ctx.log(` [FUND] ${name}: $${sum.toFixed(4)} funding received`);
|