perp-cli 0.6.3 → 0.7.1
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/README.md +7 -2
- package/dist/api/public/hyperliquid.d.ts +2 -2
- package/dist/api/public/hyperliquid.js +0 -10
- package/dist/api/public/lighter.d.ts +2 -1
- package/dist/api/public/pacifica.d.ts +2 -1
- package/dist/arb/index.d.ts +7 -4
- package/dist/arb/index.js +5 -4
- package/dist/arb/sizing.d.ts +1 -1
- package/dist/arb/state.d.ts +1 -1
- package/dist/arb/state.js +4 -3
- package/dist/arb/utils.d.ts +0 -10
- package/dist/arb/utils.js +0 -42
- package/dist/bot/apex/guard.d.ts +26 -0
- package/dist/bot/apex/guard.js +86 -0
- package/dist/bot/apex/index.d.ts +6 -0
- package/dist/bot/apex/index.js +4 -0
- package/dist/bot/apex/pulse.d.ts +22 -0
- package/dist/bot/apex/pulse.js +107 -0
- package/dist/bot/apex/radar.d.ts +17 -0
- package/dist/bot/apex/radar.js +150 -0
- package/dist/bot/conditions.d.ts +1 -1
- package/dist/bot/config.d.ts +5 -1
- package/dist/bot/config.js +1 -1
- package/dist/bot/engine.d.ts +23 -2
- package/dist/bot/engine.js +296 -351
- package/dist/bot/index.d.ts +16 -0
- package/dist/bot/index.js +10 -0
- package/dist/bot/indicators.d.ts +29 -0
- package/dist/bot/indicators.js +144 -0
- package/dist/bot/reflect.d.ts +34 -0
- package/dist/bot/reflect.js +155 -0
- package/dist/bot/strategies/aggressive-taker.d.ts +36 -0
- package/dist/bot/strategies/aggressive-taker.js +125 -0
- package/dist/bot/strategies/apex-strategy.d.ts +36 -0
- package/dist/bot/strategies/apex-strategy.js +185 -0
- package/dist/bot/strategies/avellaneda-mm.d.ts +27 -0
- package/dist/bot/strategies/avellaneda-mm.js +111 -0
- package/dist/bot/strategies/basis-arb.d.ts +27 -0
- package/dist/bot/strategies/basis-arb.js +97 -0
- package/dist/bot/strategies/claude-agent.d.ts +31 -0
- package/dist/bot/strategies/claude-agent.js +155 -0
- package/dist/bot/strategies/dca-strategy.d.ts +25 -0
- package/dist/bot/strategies/dca-strategy.js +59 -0
- package/dist/bot/strategies/engine-mm.d.ts +29 -0
- package/dist/bot/strategies/engine-mm.js +141 -0
- package/dist/bot/strategies/funding-arb-strategy.d.ts +32 -0
- package/dist/bot/strategies/funding-arb-strategy.js +168 -0
- package/dist/bot/strategies/funding-arb-v2.d.ts +32 -0
- package/dist/bot/strategies/funding-arb-v2.js +222 -0
- package/dist/bot/strategies/funding-auto.d.ts +1 -0
- package/dist/bot/strategies/funding-auto.js +572 -0
- package/dist/bot/strategies/grid-mm.d.ts +25 -0
- package/dist/bot/strategies/grid-mm.js +99 -0
- package/dist/bot/strategies/grid-strategy.d.ts +39 -0
- package/dist/bot/strategies/grid-strategy.js +176 -0
- package/dist/bot/strategies/hedge-agent.d.ts +25 -0
- package/dist/bot/strategies/hedge-agent.js +79 -0
- package/dist/bot/strategies/liquidation-mm.d.ts +25 -0
- package/dist/bot/strategies/liquidation-mm.js +108 -0
- package/dist/bot/strategies/mean-reversion.d.ts +35 -0
- package/dist/bot/strategies/mean-reversion.js +118 -0
- package/dist/bot/strategies/momentum-breakout.d.ts +36 -0
- package/dist/bot/strategies/momentum-breakout.js +159 -0
- package/dist/bot/strategies/regime-mm.d.ts +25 -0
- package/dist/bot/strategies/regime-mm.js +111 -0
- package/dist/bot/strategies/rfq-agent.d.ts +25 -0
- package/dist/bot/strategies/rfq-agent.js +71 -0
- package/dist/bot/strategies/simple-mm.d.ts +25 -0
- package/dist/bot/strategies/simple-mm.js +76 -0
- package/dist/bot/strategy-registry.d.ts +9 -0
- package/dist/bot/strategy-registry.js +14 -0
- package/dist/bot/strategy-types.d.ts +64 -0
- package/dist/bot/strategy-types.js +5 -0
- package/dist/bot/trade-journal.d.ts +27 -0
- package/dist/bot/trade-journal.js +53 -0
- package/dist/bot/tui/BotDashboard.d.ts +49 -0
- package/dist/bot/tui/BotDashboard.js +93 -0
- package/dist/bot/tui/index.d.ts +6 -0
- package/dist/bot/tui/index.js +8 -0
- package/dist/bridge-engine.d.ts +0 -1
- package/dist/bridge-engine.js +0 -1
- package/dist/cache.d.ts +0 -1
- package/dist/cache.js +0 -1
- package/dist/commands/account.d.ts +1 -1
- package/dist/commands/account.js +106 -75
- package/dist/commands/agent.d.ts +1 -1
- package/dist/commands/arb/index.d.ts +1 -1
- package/dist/commands/arb/index.js +1 -1
- package/dist/commands/arb-auto.d.ts +1 -1
- package/dist/commands/arb-auto.js +1 -1
- package/dist/commands/arb.d.ts +1 -1
- package/dist/commands/bot.d.ts +1 -1
- package/dist/commands/bot.js +198 -14
- package/dist/commands/dashboard.d.ts +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/funds.d.ts +1 -1
- package/dist/commands/funds.js +33 -20
- package/dist/commands/history.d.ts +1 -1
- package/dist/commands/history.js +5 -4
- package/dist/commands/manage.d.ts +2 -3
- package/dist/commands/manage.js +11 -18
- package/dist/commands/market.d.ts +1 -1
- package/dist/commands/market.js +7 -7
- package/dist/commands/plan.d.ts +1 -1
- package/dist/commands/rebalance.d.ts +1 -1
- package/dist/commands/rebalance.js +8 -9
- package/dist/commands/risk.d.ts +1 -1
- package/dist/commands/settings.d.ts +1 -1
- package/dist/commands/settings.js +3 -1
- package/dist/commands/trade.d.ts +1 -1
- package/dist/commands/trade.js +39 -52
- package/dist/commands/wallet.d.ts +0 -2
- package/dist/commands/wallet.js +0 -5
- package/dist/constants.d.ts +0 -3
- package/dist/constants.js +0 -4
- package/dist/cross-chain-margin.d.ts +1 -1
- package/dist/dashboard/index.d.ts +4 -0
- package/dist/dashboard/index.js +3 -0
- package/dist/dashboard/server.d.ts +1 -1
- package/dist/dashboard/server.js +1 -1
- package/dist/dashboard/ws-feeds.d.ts +1 -1
- package/dist/event-stream.d.ts +1 -1
- package/dist/exchanges/aster.d.ts +58 -0
- package/dist/exchanges/aster.js +409 -0
- package/dist/exchanges/capabilities.d.ts +74 -0
- package/dist/exchanges/capabilities.js +44 -0
- package/dist/exchanges/hyperliquid-spot.d.ts +1 -1
- package/dist/exchanges/hyperliquid-spot.js +20 -12
- package/dist/exchanges/hyperliquid.d.ts +8 -2
- package/dist/exchanges/hyperliquid.js +21 -6
- package/dist/exchanges/index.d.ts +11 -0
- package/dist/exchanges/index.js +10 -0
- package/dist/exchanges/interface.d.ts +3 -0
- package/dist/exchanges/lighter-spot.d.ts +13 -0
- package/dist/exchanges/lighter-spot.js +98 -26
- package/dist/exchanges/lighter.d.ts +9 -3
- package/dist/exchanges/lighter.js +18 -8
- package/dist/exchanges/nado.d.ts +52 -0
- package/dist/exchanges/nado.js +223 -0
- package/dist/exchanges/pacifica.d.ts +7 -1
- package/dist/exchanges/pacifica.js +17 -2
- package/dist/exchanges/registry.d.ts +13 -0
- package/dist/exchanges/registry.js +37 -0
- package/dist/exchanges/spot-interface.d.ts +9 -0
- package/dist/funding/rates.js +1 -1
- package/dist/index.js +2 -6
- package/dist/jobs.js +1 -1
- package/dist/liquidity.d.ts +1 -2
- package/dist/liquidity.js +12 -5
- package/dist/mcp-server.js +4 -2
- package/dist/pacifica/constants.d.ts +0 -3
- package/dist/pacifica/constants.js +0 -4
- package/dist/pacifica/types/account.d.ts +0 -8
- package/dist/pacifica/types/lake.d.ts +0 -6
- package/dist/pacifica/types/position.d.ts +0 -12
- package/dist/pacifica/types/ws.d.ts +0 -24
- package/dist/pacifica/types/ws.js +1 -41
- package/dist/plan-executor.d.ts +1 -1
- package/dist/rebalance.d.ts +1 -7
- package/dist/rebalance.js +0 -6
- package/dist/risk.d.ts +1 -1
- package/dist/risk.js +3 -1
- package/dist/smart-order.d.ts +1 -1
- package/dist/strategies/dca.d.ts +1 -1
- package/dist/strategies/funding-arb.d.ts +1 -1
- package/dist/strategies/funding-arb.js +193 -181
- package/dist/strategies/grid.d.ts +1 -1
- package/dist/strategies/grid.js +1 -1
- package/dist/strategies/index.d.ts +12 -0
- package/dist/strategies/index.js +7 -0
- package/dist/strategies/split-order.d.ts +1 -1
- package/dist/strategies/trailing-stop.d.ts +1 -1
- package/dist/strategies/twap.d.ts +1 -1
- package/dist/trade-validator.d.ts +1 -1
- package/package.json +7 -1
- package/skills/perp-cli/SKILL.md +20 -0
- package/skills/perp-cli/references/commands.md +22 -8
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ Same EVM key works for both Hyperliquid and Lighter.
|
|
|
48
48
|
| `account` | Balance, positions, orders, margin |
|
|
49
49
|
| `trade` | Market/limit/stop orders, close, scale, split execution |
|
|
50
50
|
| `arb` | Funding rate arb — scan, exec, close, monitor (perp-perp & spot-perp) |
|
|
51
|
-
| `bot` |
|
|
51
|
+
| `bot` | 19 strategies, APEX orchestrator, REFLECT analytics, presets |
|
|
52
52
|
| `funds` | Deposit, withdraw, transfer, CCTP bridge |
|
|
53
53
|
| `bridge` | Cross-chain USDC bridge (deBridge DLN) |
|
|
54
54
|
| `risk` | Risk limits, liquidation distance, guardrails |
|
|
@@ -121,7 +121,12 @@ perp --json funds info # all routes & limits
|
|
|
121
121
|
perp --json risk limits --max-leverage 5
|
|
122
122
|
perp --json risk liquidation-distance
|
|
123
123
|
|
|
124
|
-
# Bots
|
|
124
|
+
# Bots (19 strategies)
|
|
125
|
+
perp bot list-strategies # list all available strategies
|
|
126
|
+
perp bot run <strategy> [symbol] # run any strategy
|
|
127
|
+
perp bot apex [symbol] # APEX autonomous orchestrator
|
|
128
|
+
perp bot reflect # trading performance analysis
|
|
129
|
+
perp bot preset-list # list strategy presets
|
|
125
130
|
perp --json bot twap <SYM> buy <SIZE> 30m
|
|
126
131
|
perp --json bot grid <SYM> --range 5 --grids 10 --size 100
|
|
127
132
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
interface HyperliquidAsset {
|
|
2
2
|
symbol: string;
|
|
3
3
|
funding: number;
|
|
4
4
|
markPx: number;
|
|
@@ -9,10 +9,10 @@ export declare function parseHyperliquidMetaRaw(raw: unknown): {
|
|
|
9
9
|
rates: Map<string, number>;
|
|
10
10
|
prices: Map<string, number>;
|
|
11
11
|
};
|
|
12
|
-
export declare function fetchHyperliquidAllMids(): Promise<Record<string, string>>;
|
|
13
12
|
export declare function fetchHyperliquidAllMidsRaw(): Promise<unknown>;
|
|
14
13
|
export declare function pingHyperliquid(): Promise<{
|
|
15
14
|
ok: boolean;
|
|
16
15
|
latencyMs: number;
|
|
17
16
|
status: number;
|
|
18
17
|
}>;
|
|
18
|
+
export {};
|
|
@@ -52,16 +52,6 @@ export function parseHyperliquidMetaRaw(raw) {
|
|
|
52
52
|
});
|
|
53
53
|
return { rates, prices };
|
|
54
54
|
}
|
|
55
|
-
export function fetchHyperliquidAllMids() {
|
|
56
|
-
return withCache("pub:hl:allMids", TTL_MARKET, async () => {
|
|
57
|
-
try {
|
|
58
|
-
return await hlPost("allMids");
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return {};
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
55
|
export function fetchHyperliquidAllMidsRaw() {
|
|
66
56
|
return withCache("pub:hl:allMids:raw", TTL_MARKET, () => hlPost("allMids").catch(() => null));
|
|
67
57
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
interface LighterMarketDetail {
|
|
2
2
|
marketId: number;
|
|
3
3
|
symbol: string;
|
|
4
4
|
lastTradePrice: number;
|
|
@@ -22,3 +22,4 @@ export declare function pingLighter(): Promise<{
|
|
|
22
22
|
latencyMs: number;
|
|
23
23
|
status: number;
|
|
24
24
|
}>;
|
|
25
|
+
export {};
|
package/dist/arb/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
1
|
+
export { computeMatchedSize, computeSpotPerpMatchedSize, reconcileArbFills } from "./sizing.js";
|
|
2
|
+
export { SETTLEMENT_SCHEDULES, getLastSettlement, getMinutesSinceSettlement, aggressiveSettleBoost, estimateFundingUntilSettlement, computeBasisRisk, formatNotifyMessage, sendNotification, notifyIfEnabled, } from "./utils.js";
|
|
3
|
+
export type { SettleStrategy, BasisRisk, ArbNotifyEvent } from "./utils.js";
|
|
4
|
+
export { setStateFilePath, resetStateFilePath, loadArbState, saveArbState, addPosition, removePosition, updatePosition, getPositions, createInitialState, } from "./state.js";
|
|
5
|
+
export type { ArbPositionState, ArbDaemonState } from "./state.js";
|
|
6
|
+
export { computeEnhancedStats } from "./history-stats.js";
|
|
7
|
+
export type { ArbTradeForStats, ExchangePairPerf, TimeOfDayPerf, EnhancedHistoryStats } from "./history-stats.js";
|
package/dist/arb/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
1
|
+
// arb/ barrel — public API
|
|
2
|
+
export { computeMatchedSize, computeSpotPerpMatchedSize, reconcileArbFills } from "./sizing.js";
|
|
3
|
+
export { SETTLEMENT_SCHEDULES, getLastSettlement, getMinutesSinceSettlement, aggressiveSettleBoost, estimateFundingUntilSettlement, computeBasisRisk, formatNotifyMessage, sendNotification, notifyIfEnabled, } from "./utils.js";
|
|
4
|
+
export { setStateFilePath, resetStateFilePath, loadArbState, saveArbState, addPosition, removePosition, updatePosition, getPositions, createInitialState, } from "./state.js";
|
|
5
|
+
export { computeEnhancedStats } from "./history-stats.js";
|
package/dist/arb/sizing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExchangeAdapter } from "../exchanges/
|
|
1
|
+
import type { ExchangeAdapter } from "../exchanges/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Calculate the exact same size for both legs of an arb position,
|
|
4
4
|
* respecting both exchanges' minimum order and size precision constraints.
|
package/dist/arb/state.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export declare function loadArbState(): ArbDaemonState | null;
|
|
|
45
45
|
* If crash occurs mid-write, .tmp is partial but main file is intact.
|
|
46
46
|
*/
|
|
47
47
|
export declare function saveArbState(state: ArbDaemonState): void;
|
|
48
|
-
/** Add a position to the persisted state. */
|
|
48
|
+
/** Add a position to the persisted state. Auto-initializes state if missing. */
|
|
49
49
|
export declare function addPosition(pos: ArbPositionState): void;
|
|
50
50
|
/** Remove a position by symbol from the persisted state. */
|
|
51
51
|
export declare function removePosition(symbol: string): void;
|
package/dist/arb/state.js
CHANGED
|
@@ -62,11 +62,12 @@ export function saveArbState(state) {
|
|
|
62
62
|
writeFileSync(tmpPath, json, { mode: 0o600 });
|
|
63
63
|
renameSync(tmpPath, stateFilePath);
|
|
64
64
|
}
|
|
65
|
-
/** Add a position to the persisted state. */
|
|
65
|
+
/** Add a position to the persisted state. Auto-initializes state if missing. */
|
|
66
66
|
export function addPosition(pos) {
|
|
67
|
-
|
|
67
|
+
let state = loadArbState();
|
|
68
68
|
if (!state) {
|
|
69
|
-
|
|
69
|
+
// State was lost — create minimal valid state to avoid losing position tracking
|
|
70
|
+
state = createInitialState({ minSpread: 0, closeSpread: 0, size: 0, holdDays: 0, bridgeCost: 0, maxPositions: 10, settleStrategy: "off" });
|
|
70
71
|
}
|
|
71
72
|
// Avoid duplicates by symbol
|
|
72
73
|
state.positions = state.positions.filter(p => p.symbol !== pos.symbol);
|
package/dist/arb/utils.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Arb utilities: settlement timing strategy, basis risk monitoring, and webhook notifications.
|
|
3
3
|
*/
|
|
4
|
-
import type { ExchangeAdapter } from "../exchanges/interface.js";
|
|
5
4
|
/** Settlement schedules per exchange (UTC hours when settlement occurs) */
|
|
6
5
|
export declare const SETTLEMENT_SCHEDULES: Record<string, number[]>;
|
|
7
6
|
export type SettleStrategy = "block" | "aggressive" | "off";
|
|
@@ -47,15 +46,6 @@ export interface BasisRisk {
|
|
|
47
46
|
divergencePct: number;
|
|
48
47
|
warning: boolean;
|
|
49
48
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Check basis risk (mark price divergence) for open arb positions.
|
|
52
|
-
* Fetches current mark prices from each exchange and computes divergence.
|
|
53
|
-
*/
|
|
54
|
-
export declare function checkBasisRisk(positions: Array<{
|
|
55
|
-
symbol: string;
|
|
56
|
-
longExchange: string;
|
|
57
|
-
shortExchange: string;
|
|
58
|
-
}>, adapters: Map<string, ExchangeAdapter>, maxDivergencePct?: number): Promise<BasisRisk[]>;
|
|
59
49
|
/**
|
|
60
50
|
* Compute basis risk from pre-fetched prices (no async, for use in tests and monitor).
|
|
61
51
|
*/
|
package/dist/arb/utils.js
CHANGED
|
@@ -89,48 +89,6 @@ export function estimateFundingUntilSettlement(hlHourlyRate, pacHourlyRate, posi
|
|
|
89
89
|
const netFunding = hlCumulative - pacPayment;
|
|
90
90
|
return { hlCumulative, pacPayment, netFunding };
|
|
91
91
|
}
|
|
92
|
-
/**
|
|
93
|
-
* Check basis risk (mark price divergence) for open arb positions.
|
|
94
|
-
* Fetches current mark prices from each exchange and computes divergence.
|
|
95
|
-
*/
|
|
96
|
-
export async function checkBasisRisk(positions, adapters, maxDivergencePct = 3) {
|
|
97
|
-
const results = [];
|
|
98
|
-
for (const pos of positions) {
|
|
99
|
-
const longAdapter = adapters.get(pos.longExchange);
|
|
100
|
-
const shortAdapter = adapters.get(pos.shortExchange);
|
|
101
|
-
if (!longAdapter || !shortAdapter)
|
|
102
|
-
continue;
|
|
103
|
-
try {
|
|
104
|
-
const [longMarkets, shortMarkets] = await Promise.all([
|
|
105
|
-
longAdapter.getMarkets(),
|
|
106
|
-
shortAdapter.getMarkets(),
|
|
107
|
-
]);
|
|
108
|
-
const longMarket = longMarkets.find(m => m.symbol.replace("-PERP", "").toUpperCase() === pos.symbol.toUpperCase());
|
|
109
|
-
const shortMarket = shortMarkets.find(m => m.symbol.replace("-PERP", "").toUpperCase() === pos.symbol.toUpperCase());
|
|
110
|
-
if (!longMarket || !shortMarket)
|
|
111
|
-
continue;
|
|
112
|
-
const longPrice = Number(longMarket.markPrice);
|
|
113
|
-
const shortPrice = Number(shortMarket.markPrice);
|
|
114
|
-
if (longPrice <= 0 || shortPrice <= 0)
|
|
115
|
-
continue;
|
|
116
|
-
const avgPrice = (longPrice + shortPrice) / 2;
|
|
117
|
-
const divergencePct = Math.abs(longPrice - shortPrice) / avgPrice * 100;
|
|
118
|
-
results.push({
|
|
119
|
-
symbol: pos.symbol,
|
|
120
|
-
longExchange: pos.longExchange,
|
|
121
|
-
shortExchange: pos.shortExchange,
|
|
122
|
-
longMarkPrice: longPrice,
|
|
123
|
-
shortMarkPrice: shortPrice,
|
|
124
|
-
divergencePct,
|
|
125
|
-
warning: divergencePct >= maxDivergencePct,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
// Skip positions where we can't fetch prices
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return results;
|
|
133
|
-
}
|
|
134
92
|
/**
|
|
135
93
|
* Compute basis risk from pre-fetched prices (no async, for use in tests and monitor).
|
|
136
94
|
*/
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guard: 2-phase trailing stop with profit-locking tiers.
|
|
3
|
+
* Phase 1: wide retrace tolerance while position builds.
|
|
4
|
+
* Phase 2: tiered profit floors (e.g., at 3% ROE lock 1%, at 6% lock 3%, etc.)
|
|
5
|
+
*/
|
|
6
|
+
export interface GuardConfig {
|
|
7
|
+
/** Max retrace from entry allowed in Phase 1 (percentage, e.g., 2 = 2%) */
|
|
8
|
+
phase1MaxRetrace: number;
|
|
9
|
+
/** ROE threshold to transition from Phase 1 to Phase 2 (percentage) */
|
|
10
|
+
phase2Trigger: number;
|
|
11
|
+
/** Profit-locking tiers: [roeTrigger, floorRoe] pairs sorted ascending */
|
|
12
|
+
profitTiers: [number, number][];
|
|
13
|
+
/** Hard stop loss from entry (percentage, e.g., 5 = -5%) */
|
|
14
|
+
hardStop: number;
|
|
15
|
+
}
|
|
16
|
+
export interface GuardState {
|
|
17
|
+
phase: 1 | 2;
|
|
18
|
+
peakRoe: number;
|
|
19
|
+
currentFloor: number;
|
|
20
|
+
}
|
|
21
|
+
export declare const GUARD_PRESETS: Record<string, GuardConfig>;
|
|
22
|
+
export declare function createGuardState(): GuardState;
|
|
23
|
+
export declare function evaluateGuard(roe: number, state: GuardState, config: GuardConfig): {
|
|
24
|
+
action: "hold" | "close";
|
|
25
|
+
newState: GuardState;
|
|
26
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guard: 2-phase trailing stop with profit-locking tiers.
|
|
3
|
+
* Phase 1: wide retrace tolerance while position builds.
|
|
4
|
+
* Phase 2: tiered profit floors (e.g., at 3% ROE lock 1%, at 6% lock 3%, etc.)
|
|
5
|
+
*/
|
|
6
|
+
export const GUARD_PRESETS = {
|
|
7
|
+
conservative: {
|
|
8
|
+
phase1MaxRetrace: 1.5,
|
|
9
|
+
phase2Trigger: 1.5,
|
|
10
|
+
profitTiers: [[1.5, 0.5], [3, 1.5], [5, 3], [8, 5], [12, 8]],
|
|
11
|
+
hardStop: 3,
|
|
12
|
+
},
|
|
13
|
+
moderate: {
|
|
14
|
+
phase1MaxRetrace: 2.5,
|
|
15
|
+
phase2Trigger: 2,
|
|
16
|
+
profitTiers: [[2, 0.5], [3, 1], [5, 2.5], [8, 5], [12, 8], [20, 15]],
|
|
17
|
+
hardStop: 5,
|
|
18
|
+
},
|
|
19
|
+
aggressive: {
|
|
20
|
+
phase1MaxRetrace: 4,
|
|
21
|
+
phase2Trigger: 3,
|
|
22
|
+
profitTiers: [[3, 1], [6, 3], [10, 6], [15, 10], [25, 18]],
|
|
23
|
+
hardStop: 8,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export function createGuardState() {
|
|
27
|
+
return { phase: 1, peakRoe: 0, currentFloor: 0 };
|
|
28
|
+
}
|
|
29
|
+
export function evaluateGuard(roe, state, config) {
|
|
30
|
+
// Update peak ROE
|
|
31
|
+
const peakRoe = Math.max(state.peakRoe, roe);
|
|
32
|
+
// Hard stop: always active
|
|
33
|
+
if (roe <= -config.hardStop) {
|
|
34
|
+
return {
|
|
35
|
+
action: "close",
|
|
36
|
+
newState: { ...state, peakRoe },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// ── Phase 1: wide retrace tolerance ──
|
|
40
|
+
if (state.phase === 1) {
|
|
41
|
+
// Check if we should transition to Phase 2
|
|
42
|
+
if (roe >= config.phase2Trigger) {
|
|
43
|
+
// Transition to Phase 2 — find the current floor
|
|
44
|
+
let floor = 0;
|
|
45
|
+
for (const [trigger, lockFloor] of config.profitTiers) {
|
|
46
|
+
if (roe >= trigger)
|
|
47
|
+
floor = lockFloor;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
action: "hold",
|
|
51
|
+
newState: { phase: 2, peakRoe, currentFloor: floor },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Phase 1: allow retrace up to phase1MaxRetrace from peak
|
|
55
|
+
const retrace = peakRoe - roe;
|
|
56
|
+
if (retrace > config.phase1MaxRetrace) {
|
|
57
|
+
return {
|
|
58
|
+
action: "close",
|
|
59
|
+
newState: { ...state, peakRoe },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
action: "hold",
|
|
64
|
+
newState: { phase: 1, peakRoe, currentFloor: 0 },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// ── Phase 2: tiered profit floors ──
|
|
68
|
+
// Update floor based on current ROE
|
|
69
|
+
let floor = state.currentFloor;
|
|
70
|
+
for (const [trigger, lockFloor] of config.profitTiers) {
|
|
71
|
+
if (roe >= trigger && lockFloor > floor) {
|
|
72
|
+
floor = lockFloor;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Check if ROE dropped below current floor
|
|
76
|
+
if (roe < floor) {
|
|
77
|
+
return {
|
|
78
|
+
action: "close",
|
|
79
|
+
newState: { phase: 2, peakRoe, currentFloor: floor },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
action: "hold",
|
|
84
|
+
newState: { phase: 2, peakRoe, currentFloor: floor },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { scoreOpportunity } from "./radar.js";
|
|
2
|
+
export type { RadarScore } from "./radar.js";
|
|
3
|
+
export { detectPulse, tierRank } from "./pulse.js";
|
|
4
|
+
export type { PulseTier, PulseSignal } from "./pulse.js";
|
|
5
|
+
export { evaluateGuard, createGuardState, GUARD_PRESETS } from "./guard.js";
|
|
6
|
+
export type { GuardConfig, GuardState } from "./guard.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse: 5-tier signal taxonomy for momentum detection.
|
|
3
|
+
* FIRST_JUMP (100): first sector mover, OI + volume breakout
|
|
4
|
+
* CONTRIB_EXPLOSION (95): OI +15% AND volume 5x simultaneously
|
|
5
|
+
* IMMEDIATE_MOVER (80): OI +15% OR volume 5x
|
|
6
|
+
* NEW_ENTRY_DEEP (65): OI growth 8%+ with low volume (smart money)
|
|
7
|
+
* DEEP_CLIMBER (55): sustained OI climb 5%+ per window over 3+ scans
|
|
8
|
+
*/
|
|
9
|
+
import type { EnrichedSnapshot } from "../strategy-types.js";
|
|
10
|
+
export type PulseTier = "FIRST_JUMP" | "CONTRIB_EXPLOSION" | "IMMEDIATE_MOVER" | "NEW_ENTRY_DEEP" | "DEEP_CLIMBER" | "NONE";
|
|
11
|
+
export interface PulseSignal {
|
|
12
|
+
symbol: string;
|
|
13
|
+
tier: PulseTier;
|
|
14
|
+
confidence: number;
|
|
15
|
+
oiChange: number;
|
|
16
|
+
volumeRatio: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function tierRank(tier: PulseTier): number;
|
|
19
|
+
export declare function detectPulse(current: EnrichedSnapshot, history: Map<string, {
|
|
20
|
+
oi: number;
|
|
21
|
+
volume: number;
|
|
22
|
+
}[]>): PulseSignal;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse: 5-tier signal taxonomy for momentum detection.
|
|
3
|
+
* FIRST_JUMP (100): first sector mover, OI + volume breakout
|
|
4
|
+
* CONTRIB_EXPLOSION (95): OI +15% AND volume 5x simultaneously
|
|
5
|
+
* IMMEDIATE_MOVER (80): OI +15% OR volume 5x
|
|
6
|
+
* NEW_ENTRY_DEEP (65): OI growth 8%+ with low volume (smart money)
|
|
7
|
+
* DEEP_CLIMBER (55): sustained OI climb 5%+ per window over 3+ scans
|
|
8
|
+
*/
|
|
9
|
+
/** Tier ordering for comparison */
|
|
10
|
+
const TIER_RANK = {
|
|
11
|
+
FIRST_JUMP: 100,
|
|
12
|
+
CONTRIB_EXPLOSION: 95,
|
|
13
|
+
IMMEDIATE_MOVER: 80,
|
|
14
|
+
NEW_ENTRY_DEEP: 65,
|
|
15
|
+
DEEP_CLIMBER: 55,
|
|
16
|
+
NONE: 0,
|
|
17
|
+
};
|
|
18
|
+
export function tierRank(tier) {
|
|
19
|
+
return TIER_RANK[tier];
|
|
20
|
+
}
|
|
21
|
+
export function detectPulse(current, history) {
|
|
22
|
+
const symbol = "unknown"; // caller sets the actual symbol
|
|
23
|
+
const currentOi = parseFloat(current.openInterest);
|
|
24
|
+
const currentVolume = current.volume24h;
|
|
25
|
+
const past = history.get(symbol) ?? [];
|
|
26
|
+
if (past.length === 0) {
|
|
27
|
+
return { symbol, tier: "NONE", confidence: 0, oiChange: 0, volumeRatio: 0 };
|
|
28
|
+
}
|
|
29
|
+
// Compare against the most recent historical entry
|
|
30
|
+
const prev = past[past.length - 1];
|
|
31
|
+
const oiChange = prev.oi > 0 ? (currentOi - prev.oi) / prev.oi : 0;
|
|
32
|
+
const volumeRatio = prev.volume > 0 ? currentVolume / prev.volume : 0;
|
|
33
|
+
// Thresholds
|
|
34
|
+
const oiBreakout = oiChange >= 0.15; // +15%
|
|
35
|
+
const volumeBreakout = volumeRatio >= 5; // 5x volume
|
|
36
|
+
const oiDeep = oiChange >= 0.08; // +8% OI
|
|
37
|
+
const lowVolume = volumeRatio < 1.5; // below 1.5x → quiet accumulation
|
|
38
|
+
// ── Tier detection (highest priority first) ──
|
|
39
|
+
// FIRST_JUMP: OI + volume breakout when no other symbol in sector moved
|
|
40
|
+
// Simplified: both OI and volume spike with OI being the dominant factor
|
|
41
|
+
if (oiBreakout && volumeBreakout && oiChange >= 0.2) {
|
|
42
|
+
return {
|
|
43
|
+
symbol,
|
|
44
|
+
tier: "FIRST_JUMP",
|
|
45
|
+
confidence: Math.min(oiChange * 3 + volumeRatio * 0.1, 1),
|
|
46
|
+
oiChange,
|
|
47
|
+
volumeRatio,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// CONTRIB_EXPLOSION: OI +15% AND volume 5x simultaneously
|
|
51
|
+
if (oiBreakout && volumeBreakout) {
|
|
52
|
+
return {
|
|
53
|
+
symbol,
|
|
54
|
+
tier: "CONTRIB_EXPLOSION",
|
|
55
|
+
confidence: Math.min(oiChange * 2.5 + volumeRatio * 0.08, 1),
|
|
56
|
+
oiChange,
|
|
57
|
+
volumeRatio,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// IMMEDIATE_MOVER: OI +15% OR volume 5x
|
|
61
|
+
if (oiBreakout || volumeBreakout) {
|
|
62
|
+
return {
|
|
63
|
+
symbol,
|
|
64
|
+
tier: "IMMEDIATE_MOVER",
|
|
65
|
+
confidence: Math.min(Math.max(oiChange * 2, volumeRatio * 0.15), 1),
|
|
66
|
+
oiChange,
|
|
67
|
+
volumeRatio,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// NEW_ENTRY_DEEP: OI growth 8%+ with low volume (smart money accumulation)
|
|
71
|
+
if (oiDeep && lowVolume) {
|
|
72
|
+
return {
|
|
73
|
+
symbol,
|
|
74
|
+
tier: "NEW_ENTRY_DEEP",
|
|
75
|
+
confidence: Math.min(oiChange * 3, 1),
|
|
76
|
+
oiChange,
|
|
77
|
+
volumeRatio,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// DEEP_CLIMBER: sustained OI climb 5%+ per window over 3+ consecutive scans
|
|
81
|
+
if (past.length >= 3) {
|
|
82
|
+
let consecutiveClimbs = 0;
|
|
83
|
+
for (let i = 1; i < past.length; i++) {
|
|
84
|
+
const prevOi = past[i - 1].oi;
|
|
85
|
+
const currOi = past[i].oi;
|
|
86
|
+
if (prevOi > 0 && (currOi - prevOi) / prevOi >= 0.05) {
|
|
87
|
+
consecutiveClimbs++;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
consecutiveClimbs = 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Also check current vs last
|
|
94
|
+
if (prev.oi > 0 && oiChange >= 0.05)
|
|
95
|
+
consecutiveClimbs++;
|
|
96
|
+
if (consecutiveClimbs >= 3) {
|
|
97
|
+
return {
|
|
98
|
+
symbol,
|
|
99
|
+
tier: "DEEP_CLIMBER",
|
|
100
|
+
confidence: Math.min(consecutiveClimbs * 0.2, 1),
|
|
101
|
+
oiChange,
|
|
102
|
+
volumeRatio,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { symbol, tier: "NONE", confidence: 0, oiChange, volumeRatio };
|
|
107
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radar: 4-stage scoring funnel (0-400 points)
|
|
3
|
+
* Stage 1: Market Structure (35%, 0-140) -- volume, OI, liquidity depth
|
|
4
|
+
* Stage 2: Technicals (30%, 0-120) -- RSI, EMA trend, pattern
|
|
5
|
+
* Stage 3: Funding (20%, 0-80) -- rate extremes, direction bias
|
|
6
|
+
* Stage 4: BTC Macro (15%, 0-60) -- BTC trend alignment, regime
|
|
7
|
+
*/
|
|
8
|
+
import type { EnrichedSnapshot } from "../strategy-types.js";
|
|
9
|
+
export interface RadarScore {
|
|
10
|
+
symbol: string;
|
|
11
|
+
total: number;
|
|
12
|
+
structure: number;
|
|
13
|
+
technicals: number;
|
|
14
|
+
funding: number;
|
|
15
|
+
btcMacro: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function scoreOpportunity(snapshot: EnrichedSnapshot, btcSnapshot: EnrichedSnapshot | null): RadarScore;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radar: 4-stage scoring funnel (0-400 points)
|
|
3
|
+
* Stage 1: Market Structure (35%, 0-140) -- volume, OI, liquidity depth
|
|
4
|
+
* Stage 2: Technicals (30%, 0-120) -- RSI, EMA trend, pattern
|
|
5
|
+
* Stage 3: Funding (20%, 0-80) -- rate extremes, direction bias
|
|
6
|
+
* Stage 4: BTC Macro (15%, 0-60) -- BTC trend alignment, regime
|
|
7
|
+
*/
|
|
8
|
+
import { calculateEMA, calculateRSI, detectRegime } from "../indicators.js";
|
|
9
|
+
// ── Stage 1: Market Structure (0-140) ──
|
|
10
|
+
function scoreStructure(snapshot) {
|
|
11
|
+
let score = 0;
|
|
12
|
+
// Volume component (0-50): higher 24h volume = more liquid
|
|
13
|
+
const vol = snapshot.volume24h;
|
|
14
|
+
if (vol > 100_000_000)
|
|
15
|
+
score += 50;
|
|
16
|
+
else if (vol > 50_000_000)
|
|
17
|
+
score += 40;
|
|
18
|
+
else if (vol > 10_000_000)
|
|
19
|
+
score += 30;
|
|
20
|
+
else if (vol > 1_000_000)
|
|
21
|
+
score += 15;
|
|
22
|
+
// OI component (0-50): higher open interest = more conviction
|
|
23
|
+
const oi = parseFloat(snapshot.openInterest);
|
|
24
|
+
if (oi > 50_000_000)
|
|
25
|
+
score += 50;
|
|
26
|
+
else if (oi > 20_000_000)
|
|
27
|
+
score += 40;
|
|
28
|
+
else if (oi > 5_000_000)
|
|
29
|
+
score += 25;
|
|
30
|
+
else if (oi > 1_000_000)
|
|
31
|
+
score += 10;
|
|
32
|
+
// Liquidity depth component (0-40): tight spread = deep book
|
|
33
|
+
const spread = snapshot.spreadPct;
|
|
34
|
+
if (spread < 0.01)
|
|
35
|
+
score += 40;
|
|
36
|
+
else if (spread < 0.03)
|
|
37
|
+
score += 30;
|
|
38
|
+
else if (spread < 0.05)
|
|
39
|
+
score += 20;
|
|
40
|
+
else if (spread < 0.1)
|
|
41
|
+
score += 10;
|
|
42
|
+
return Math.min(score, 140);
|
|
43
|
+
}
|
|
44
|
+
// ── Stage 2: Technicals (0-120) ──
|
|
45
|
+
function scoreTechnicals(snapshot) {
|
|
46
|
+
let score = 0;
|
|
47
|
+
const klines = snapshot.klines;
|
|
48
|
+
if (klines.length < 20)
|
|
49
|
+
return 0;
|
|
50
|
+
const closes = klines.map(k => parseFloat(k.close));
|
|
51
|
+
// RSI component (0-40): extreme RSI = strong signal
|
|
52
|
+
const rsi = calculateRSI(closes, 14);
|
|
53
|
+
if (rsi <= 25 || rsi >= 75)
|
|
54
|
+
score += 40; // extreme
|
|
55
|
+
else if (rsi <= 30 || rsi >= 70)
|
|
56
|
+
score += 30; // strong
|
|
57
|
+
else if (rsi <= 35 || rsi >= 65)
|
|
58
|
+
score += 15; // moderate
|
|
59
|
+
// EMA trend alignment (0-40): price above EMA20 = bullish, below = bearish
|
|
60
|
+
const ema20 = calculateEMA(closes, 20);
|
|
61
|
+
const ema50 = calculateEMA(closes, Math.min(50, closes.length));
|
|
62
|
+
if (ema20.length > 0 && ema50.length > 0) {
|
|
63
|
+
const lastEma20 = ema20[ema20.length - 1];
|
|
64
|
+
const lastEma50 = ema50[ema50.length - 1];
|
|
65
|
+
const price = snapshot.price;
|
|
66
|
+
// Clear trend: price and short EMA aligned relative to long EMA
|
|
67
|
+
const bullTrend = price > lastEma20 && lastEma20 > lastEma50;
|
|
68
|
+
const bearTrend = price < lastEma20 && lastEma20 < lastEma50;
|
|
69
|
+
if (bullTrend || bearTrend)
|
|
70
|
+
score += 40;
|
|
71
|
+
else if (price > lastEma20 || price < lastEma20)
|
|
72
|
+
score += 15;
|
|
73
|
+
}
|
|
74
|
+
// Pattern component (0-40): recent volatility contraction then expansion
|
|
75
|
+
const recentVol = snapshot.volatility24h;
|
|
76
|
+
if (recentVol > 5)
|
|
77
|
+
score += 40; // high volatility breakout
|
|
78
|
+
else if (recentVol > 3)
|
|
79
|
+
score += 25;
|
|
80
|
+
else if (recentVol > 1.5)
|
|
81
|
+
score += 10;
|
|
82
|
+
return Math.min(score, 120);
|
|
83
|
+
}
|
|
84
|
+
// ── Stage 3: Funding (0-80) ──
|
|
85
|
+
function scoreFunding(snapshot) {
|
|
86
|
+
let score = 0;
|
|
87
|
+
const fr = snapshot.fundingRate;
|
|
88
|
+
const absFr = Math.abs(fr);
|
|
89
|
+
// Extreme funding = contrarian opportunity (0-50)
|
|
90
|
+
if (absFr > 0.001)
|
|
91
|
+
score += 50; // >0.1% per period
|
|
92
|
+
else if (absFr > 0.0005)
|
|
93
|
+
score += 35; // >0.05%
|
|
94
|
+
else if (absFr > 0.0002)
|
|
95
|
+
score += 15; // >0.02%
|
|
96
|
+
// Direction bias bonus (0-30): extreme negative = long opportunity, extreme positive = short
|
|
97
|
+
if (fr < -0.0005)
|
|
98
|
+
score += 30; // heavy short bias → long signal
|
|
99
|
+
else if (fr > 0.0005)
|
|
100
|
+
score += 30; // heavy long bias → short signal
|
|
101
|
+
else if (absFr > 0.0002)
|
|
102
|
+
score += 10;
|
|
103
|
+
return Math.min(score, 80);
|
|
104
|
+
}
|
|
105
|
+
// ── Stage 4: BTC Macro (0-60) ──
|
|
106
|
+
function scoreBtcMacro(btcSnapshot) {
|
|
107
|
+
if (!btcSnapshot)
|
|
108
|
+
return 30; // neutral if no BTC data
|
|
109
|
+
let score = 0;
|
|
110
|
+
const klines = btcSnapshot.klines;
|
|
111
|
+
if (klines.length < 20)
|
|
112
|
+
return 30;
|
|
113
|
+
const closes = klines.map(k => parseFloat(k.close));
|
|
114
|
+
const regime = detectRegime(closes, 20);
|
|
115
|
+
// Trending regime favors directional trades (0-35)
|
|
116
|
+
if (regime === "low-vol-trending")
|
|
117
|
+
score += 35;
|
|
118
|
+
else if (regime === "high-vol-trending")
|
|
119
|
+
score += 25;
|
|
120
|
+
else if (regime === "low-vol-ranging")
|
|
121
|
+
score += 10;
|
|
122
|
+
// high-vol-ranging = 0 (unfavorable)
|
|
123
|
+
// BTC trend alignment (0-25): clear BTC direction helps alts
|
|
124
|
+
const ema20 = calculateEMA(closes, 20);
|
|
125
|
+
if (ema20.length > 0) {
|
|
126
|
+
const btcPrice = btcSnapshot.price;
|
|
127
|
+
const lastEma = ema20[ema20.length - 1];
|
|
128
|
+
const pctAbove = (btcPrice - lastEma) / lastEma;
|
|
129
|
+
if (Math.abs(pctAbove) > 0.02)
|
|
130
|
+
score += 25; // strong BTC trend
|
|
131
|
+
else if (Math.abs(pctAbove) > 0.005)
|
|
132
|
+
score += 15; // moderate
|
|
133
|
+
}
|
|
134
|
+
return Math.min(score, 60);
|
|
135
|
+
}
|
|
136
|
+
// ── Main scorer ──
|
|
137
|
+
export function scoreOpportunity(snapshot, btcSnapshot) {
|
|
138
|
+
const structure = scoreStructure(snapshot);
|
|
139
|
+
const technicals = scoreTechnicals(snapshot);
|
|
140
|
+
const funding = scoreFunding(snapshot);
|
|
141
|
+
const btcMacro = scoreBtcMacro(btcSnapshot);
|
|
142
|
+
return {
|
|
143
|
+
symbol: snapshot.klines[0]?.close ? "unknown" : "unknown", // caller sets symbol
|
|
144
|
+
total: structure + technicals + funding + btcMacro,
|
|
145
|
+
structure,
|
|
146
|
+
technicals,
|
|
147
|
+
funding,
|
|
148
|
+
btcMacro,
|
|
149
|
+
};
|
|
150
|
+
}
|
package/dist/bot/conditions.d.ts
CHANGED
package/dist/bot/config.d.ts
CHANGED
|
@@ -40,7 +40,11 @@ export interface FundingArbStrategyParams {
|
|
|
40
40
|
max_positions: number;
|
|
41
41
|
exchanges: string[];
|
|
42
42
|
}
|
|
43
|
-
export
|
|
43
|
+
export interface GenericStrategyParams {
|
|
44
|
+
type: string;
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
}
|
|
47
|
+
export type StrategyParams = GridStrategyParams | DCAStrategyParams | FundingArbStrategyParams | GenericStrategyParams;
|
|
44
48
|
export interface BotConfig {
|
|
45
49
|
name: string;
|
|
46
50
|
exchange: string;
|