perp-cli 0.7.37 → 0.7.39
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/bot/config.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export class FundingArbStrategy {
|
|
|
16
16
|
{ name: "max_positions", type: "number", required: false, default: 3, description: "Max concurrent positions" },
|
|
17
17
|
{ name: "exchanges", type: "string", required: true, description: "Comma-separated exchange names" },
|
|
18
18
|
{ name: "leverage", type: "number", required: false, default: 3, description: "Max leverage to use" },
|
|
19
|
+
{ name: "min_hold_hours", type: "number", required: false, default: 2, description: "Min hold time before close (hours)" },
|
|
19
20
|
],
|
|
20
21
|
};
|
|
21
22
|
}
|
|
@@ -88,7 +89,7 @@ export class FundingArbStrategy {
|
|
|
88
89
|
const longEx = pA.side === "long" ? exA : exB;
|
|
89
90
|
const shortEx = pA.side === "short" ? exA : exB;
|
|
90
91
|
const size = pA.side === "long" ? pA.size : pB.size;
|
|
91
|
-
recovered.push({ symbol: pA.symbol, longExchange: longEx, shortExchange: shortEx, entrySpread: 0, size, mode: "perp-perp" });
|
|
92
|
+
recovered.push({ symbol: pA.symbol, longExchange: longEx, shortExchange: shortEx, entrySpread: 0, size, mode: "perp-perp", entryTime: 0 });
|
|
92
93
|
used.add(keyA);
|
|
93
94
|
used.add(keyB);
|
|
94
95
|
break;
|
|
@@ -135,7 +136,7 @@ export class FundingArbStrategy {
|
|
|
135
136
|
const spotBal = nonUsdc.find(b => b.token.toUpperCase().replace(/-SPOT$/, "") === base);
|
|
136
137
|
ctx.log(` [ARB] ${name} perp ${perp.symbol}(${perp.side}) → base=${base}, spotMatch=${spotBal ? spotBal.token : "none"}`);
|
|
137
138
|
if (spotBal && perp.side === "short") {
|
|
138
|
-
recovered.push({ symbol: base, longExchange: `${name}-spot`, shortExchange: name, entrySpread: 0, size: perp.size, mode: "spot-perp" });
|
|
139
|
+
recovered.push({ symbol: base, longExchange: `${name}-spot`, shortExchange: name, entrySpread: 0, size: perp.size, mode: "spot-perp", entryTime: 0 });
|
|
139
140
|
used.add(perpKey);
|
|
140
141
|
ctx.log(` [ARB] Detected spot-perp hedge: ${base} ${name}-spot↔${name}`);
|
|
141
142
|
}
|
|
@@ -273,7 +274,10 @@ export class FundingArbStrategy {
|
|
|
273
274
|
signedSpread = (shortHourly - longHourly) * 8760 * 100;
|
|
274
275
|
}
|
|
275
276
|
// Close if funding flipped (losing money) or spread below close threshold
|
|
276
|
-
const
|
|
277
|
+
const minHoldMs = (params.min_hold_hours ?? 2) * 60 * 60 * 1000;
|
|
278
|
+
const holdTime = pos.entryTime > 0 ? Date.now() - pos.entryTime : Infinity;
|
|
279
|
+
const isFundingFlipped = signedSpread < 0;
|
|
280
|
+
const shouldClose = isFundingFlipped || (holdTime >= minHoldMs && signedSpread < params.close_spread);
|
|
277
281
|
if (shouldClose) {
|
|
278
282
|
// Cooldown: skip if close recently failed for this symbol
|
|
279
283
|
const closeKey = `${pos.symbol}:close`;
|
|
@@ -577,8 +581,10 @@ export class FundingArbStrategy {
|
|
|
577
581
|
longAdapter.getPositions(),
|
|
578
582
|
shortAdapter.getPositions(),
|
|
579
583
|
]);
|
|
580
|
-
const
|
|
581
|
-
const
|
|
584
|
+
const symUpper = best.symbol.toUpperCase();
|
|
585
|
+
const matchSymbol = (s) => { const u = s.toUpperCase(); return u === symUpper || u === symUpper + "-PERP" || u.replace(/-PERP$/, "") === symUpper; };
|
|
586
|
+
const longExists = longPositions.some(p => matchSymbol(p.symbol) && parseFloat(p.size) > 0);
|
|
587
|
+
const shortExists = shortPositions.some(p => matchSymbol(p.symbol) && parseFloat(p.size) > 0);
|
|
582
588
|
if (!longExists && !shortExists) {
|
|
583
589
|
// Both missing likely means cache issue — log warning but don't rollback
|
|
584
590
|
ctx.log(` [ARB] Position verification: both sides not visible for ${best.symbol} (may be cache delay)`);
|
|
@@ -617,6 +623,7 @@ export class FundingArbStrategy {
|
|
|
617
623
|
entrySpread: best.spread,
|
|
618
624
|
size: matched.size,
|
|
619
625
|
mode: "perp-perp",
|
|
626
|
+
entryTime: Date.now(),
|
|
620
627
|
});
|
|
621
628
|
ctx.state.set("arbOpenPositions", currentPositions);
|
|
622
629
|
ctx.state.set("arbPositions", currentPositions.length);
|
|
@@ -875,6 +882,7 @@ export class FundingArbStrategy {
|
|
|
875
882
|
entrySpread: opp.spread,
|
|
876
883
|
size: matched.size,
|
|
877
884
|
mode: "spot-perp",
|
|
885
|
+
entryTime: Date.now(),
|
|
878
886
|
});
|
|
879
887
|
ctx.state.set("arbOpenPositions", currentPositions);
|
|
880
888
|
ctx.state.set("arbPositions", currentPositions.length);
|