@solard/cli 0.2.20 → 0.2.22
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/package.json +6 -4
- package/src/index.ts +16 -25
- package/src/launch-watch-command.ts +153 -52
- package/src/price-feed-client.ts +168 -2
- package/src/price-feed-protocol.ts +51 -8
- package/src/price-feed-server.architecture.test.ts +21 -0
- package/src/price-feed-server.ts +286 -1386
- package/src/trade-strategy-command.ts +28 -38
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
type Logs,
|
|
8
8
|
type ParsedTransactionWithMeta,
|
|
9
9
|
} from "@solana/web3.js";
|
|
10
|
-
import { connectPriceFeed } from "./price-feed-client.ts";
|
|
11
|
-
import type { PriceFeedPrice } from "./price-feed-protocol.ts";
|
|
12
10
|
import {
|
|
13
11
|
RaydiumService,
|
|
14
12
|
createTraderSolard,
|
|
15
13
|
resolveTradeAsset,
|
|
16
14
|
sol,
|
|
15
|
+
subscribeTrades,
|
|
16
|
+
type TradeEvent,
|
|
17
17
|
} from "@solard/core";
|
|
18
18
|
|
|
19
19
|
type Flags = Map<string, string>;
|
|
@@ -1003,14 +1003,10 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1003
1003
|
Math.trunc(numberFlag(args.flags, "heartbeat-ms", 15_000)),
|
|
1004
1004
|
);
|
|
1005
1005
|
const rpc = rpcUrl(args.flags);
|
|
1006
|
-
const feed =
|
|
1007
|
-
flag(args.flags, "feed") ??
|
|
1008
|
-
process.env.SOLARD_FEED_URL?.trim() ??
|
|
1009
|
-
"ws://127.0.0.1:8788/ws";
|
|
1010
1006
|
const strategy = await loadStrategy(path);
|
|
1011
1007
|
if (typeof strategy.onPrice !== "function")
|
|
1012
1008
|
throw new Error(
|
|
1013
|
-
`Live
|
|
1009
|
+
`Live trade strategy ${path} must define onPrice(ctx, price). ` +
|
|
1014
1010
|
`Legacy onTrade is retained for historical exact-trade backtests, not per-agent live RPC subscriptions.`,
|
|
1015
1011
|
);
|
|
1016
1012
|
const state = await initialState(strategy);
|
|
@@ -1021,8 +1017,7 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1021
1017
|
let priceCount = 0;
|
|
1022
1018
|
let lastPrice: StrategyPriceTick | null = null;
|
|
1023
1019
|
let callbackErrors = 0;
|
|
1024
|
-
let
|
|
1025
|
-
let feedConnected = false;
|
|
1020
|
+
let marketErrors = 0;
|
|
1026
1021
|
let callbackQueue: Promise<void> = Promise.resolve();
|
|
1027
1022
|
|
|
1028
1023
|
try {
|
|
@@ -1139,18 +1134,20 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1139
1134
|
}
|
|
1140
1135
|
};
|
|
1141
1136
|
|
|
1142
|
-
const onPrice = async (event:
|
|
1143
|
-
if (event.mint !== mint || stopped) return;
|
|
1137
|
+
const onPrice = async (event: TradeEvent) => {
|
|
1138
|
+
if (event.mint !== mint || stopped || event.priceQuote == null) return;
|
|
1139
|
+
const priceSol = event.quoteMint === WSOL_MINT ? event.priceQuote : null;
|
|
1140
|
+
const priceUsd = event.quoteMint === USDC_MINT ? event.priceQuote : null;
|
|
1141
|
+
if (priceSol == null && priceUsd == null) return;
|
|
1144
1142
|
const price: StrategyPriceTick = {
|
|
1145
|
-
signature: event.signature
|
|
1146
|
-
slot: event.slot
|
|
1143
|
+
signature: event.signature,
|
|
1144
|
+
slot: event.slot,
|
|
1147
1145
|
atMs: event.atMs,
|
|
1148
1146
|
mint,
|
|
1149
|
-
priceSol
|
|
1150
|
-
priceUsd
|
|
1151
|
-
marketCapUsd:
|
|
1147
|
+
priceSol,
|
|
1148
|
+
priceUsd,
|
|
1149
|
+
marketCapUsd: null,
|
|
1152
1150
|
};
|
|
1153
|
-
if (price.priceSol == null && price.priceUsd == null) return;
|
|
1154
1151
|
priceCount += 1;
|
|
1155
1152
|
lastPrice = price;
|
|
1156
1153
|
if (json) report("price", price as any);
|
|
@@ -1162,21 +1159,16 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1162
1159
|
};
|
|
1163
1160
|
|
|
1164
1161
|
const controller = new AbortController();
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1162
|
+
const marketSubscription = await subscribeTrades({
|
|
1163
|
+
connection: slrd.connection(),
|
|
1164
|
+
tokens: [mint],
|
|
1168
1165
|
signal: controller.signal,
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
if (event === "connect-error") {
|
|
1172
|
-
feedConnected = false;
|
|
1173
|
-
feedErrors += 1;
|
|
1174
|
-
}
|
|
1175
|
-
report(`feed ${event}`, data ?? {});
|
|
1166
|
+
onTrade(event) {
|
|
1167
|
+
callbackQueue = callbackQueue.then(() => onPrice(event));
|
|
1176
1168
|
},
|
|
1177
|
-
|
|
1178
|
-
if (
|
|
1179
|
-
|
|
1169
|
+
onStatus(event, data) {
|
|
1170
|
+
if (event.includes("error")) marketErrors += 1;
|
|
1171
|
+
report(`market ${event}`, data ?? {});
|
|
1180
1172
|
},
|
|
1181
1173
|
});
|
|
1182
1174
|
|
|
@@ -1186,9 +1178,8 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1186
1178
|
wallet: walletRef,
|
|
1187
1179
|
walletAddress,
|
|
1188
1180
|
live,
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
upstreamMarketSubscriptions: 0,
|
|
1181
|
+
event: "direct-trade-subscription",
|
|
1182
|
+
upstreamMarketSubscriptions: marketSubscription.listTokens().length,
|
|
1192
1183
|
});
|
|
1193
1184
|
|
|
1194
1185
|
if (strategy.onStart) {
|
|
@@ -1208,11 +1199,10 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1208
1199
|
process.once("SIGTERM", stopSignal);
|
|
1209
1200
|
const heartbeatTimer = setInterval(() => {
|
|
1210
1201
|
report("strategy heartbeat", {
|
|
1211
|
-
feedConnected,
|
|
1212
1202
|
prices: priceCount,
|
|
1213
1203
|
callbackErrors,
|
|
1214
|
-
|
|
1215
|
-
upstreamMarketSubscriptions:
|
|
1204
|
+
marketErrors,
|
|
1205
|
+
upstreamMarketSubscriptions: marketSubscription.listTokens().length,
|
|
1216
1206
|
executionVenue: executor.venue ?? "unresolved",
|
|
1217
1207
|
});
|
|
1218
1208
|
}, heartbeatMs);
|
|
@@ -1224,7 +1214,7 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1224
1214
|
process.removeListener("SIGINT", stopSignal);
|
|
1225
1215
|
process.removeListener("SIGTERM", stopSignal);
|
|
1226
1216
|
controller.abort();
|
|
1227
|
-
|
|
1217
|
+
await marketSubscription.close();
|
|
1228
1218
|
await callbackQueue.catch(() => undefined);
|
|
1229
1219
|
if (strategy.onStop) {
|
|
1230
1220
|
try {
|
|
@@ -1238,7 +1228,7 @@ export async function runTradeStrategyCommand(args: {
|
|
|
1238
1228
|
reason: stopReason,
|
|
1239
1229
|
prices: priceCount,
|
|
1240
1230
|
callbackErrors,
|
|
1241
|
-
|
|
1231
|
+
marketErrors,
|
|
1242
1232
|
});
|
|
1243
1233
|
}
|
|
1244
1234
|
} finally {
|