hft-js
Version:
High-Frequency Trading in Node.js
177 lines • 6.05 kB
JavaScript
/*
* index.test.ts
*
* Copyright (c) 2025 Xiongfei Shi
*
* Author: Xiongfei Shi <xiongfei.shi(a)icloud.com>
* License: Apache-2.0
*
* https://github.com/shixiongfei/hft.js
*/
import process from "node:process";
import fs from "node:fs";
import * as hft from "./index.js";
const config = JSON.parse(fs.readFileSync("test.conf.json", "utf8"));
class Strategy {
lastTick;
lastBar;
engine;
symbol = config.Test.Symbol;
constructor(engine) {
this.engine = engine;
}
onInit() {
this.engine.subscribe([this.symbol], this);
this.engine.subscribeBar([this.symbol], this);
console.log("Strategy init");
console.log("Trading Day", this.engine.getTradingDay());
this.engine.queryInstrument(this.symbol, {
onInstrument: (instrument) => {
if (!instrument) {
console.error("Symbol", this.symbol, "error");
process.exit(1);
}
console.log("Instrument", instrument);
},
});
this.engine.queryCommissionRate(this.symbol, {
onCommissionRate: (rate) => {
console.log("Commission Rate", rate);
},
});
this.engine.queryMarginRate(this.symbol, {
onMarginRate: (rate) => {
console.log("Margin Rate", rate);
},
});
this.engine.queryTradingAccounts({
onTradingAccounts: (accounts) => {
console.log("Trading Accounts", accounts);
},
});
this.engine.queryOrders({
onOrders: (orders) => {
console.log("Orders", orders);
},
});
this.engine.queryPositionDetails({
onPositionDetails: (positionDetails) => {
console.log("Position Details", positionDetails);
},
});
this.engine.queryPositions({
onPositions: (positions) => {
console.log("Positions", positions);
},
});
setTimeout(() => {
if (!this.lastTick) {
console.error("Market data is not found");
return;
}
if (this.lastBar) {
console.log(this.lastBar);
}
const price = this.lastTick.orderBook.asks.price[0];
if (!price) {
console.error("Invalid price");
return;
}
hft.buyOpen(this.engine, this, this.symbol, 1, price, {
onPlaceOrderSent: (receiptId) => {
console.log("Open Place Order Receipt Id", receiptId);
},
onPlaceOrderError: (reason) => {
console.error("Open Place Order Error", reason);
},
});
}, 30 * 1000);
}
onDestroy() {
this.engine.unsubscribeBar([this.symbol], this);
this.engine.unsubscribe([this.symbol], this);
console.log("Strategy destroy");
}
onRisk(type, reason) {
console.log("Trigger Risk Control", type, reason);
}
onEntrust(order) {
console.log("Entrust order", order);
}
onTrade(order, trade) {
console.log("Order", order, "Traded", trade);
if (order.status === "filled") {
setTimeout(() => {
this.engine.queryPosition(this.symbol, {
onPosition: (position) => {
if (!position || !this.lastTick) {
return;
}
const todayLong = position.today.long.position - position.today.long.frozen;
if (todayLong > 0) {
if (this.lastBar) {
console.log(this.lastBar);
}
hft.sellClose(this.engine, this, this.symbol, todayLong, 0, true, {
onPlaceOrderSent: (receiptId) => {
console.log("Close Place Order Receipt Id", receiptId);
},
onPlaceOrderError: (reason) => {
console.error("Close Place Order Error", reason);
},
});
}
},
});
}, 30 * 1000);
}
}
onCancel(order) {
console.log("Cancel Order", order);
}
onReject(order) {
console.log("Reject Order", order);
}
onTick(tick, tape) {
//console.log(tick);
//console.log(tape);
this.lastTick = tick;
}
onBar(bar) {
console.log(bar);
this.lastBar = bar;
}
}
const market = hft.createMarket(config.FlowMdPath, config.FrontMdAddrs, {
listener: {
onSubscribed: (symbol) => {
console.log(`Market subscribed: ${symbol}`);
},
onUnsubscribed: (symbol) => {
console.log(`Market unsubscribed: ${symbol}`);
},
},
});
const trader = hft.createTrader(config.FlowTdPath, config.FrontTdAddrs, config.UserInfo, { fastQueryLastTick: (instrumentId) => market.getLastTick(instrumentId) });
const recorder = market.getRecorder();
const enableRecorder = false;
if (enableRecorder && recorder) {
recorder.setRecorder({
onMarketData: (marketData) => {
console.log(marketData.InstrumentID, marketData.LastPrice);
},
}, (instruments) => instruments
.filter((instrument) => instrument.productType === "futures")
.map((instrument) => instrument.symbol));
}
const broker = hft.createBroker(trader, market, {
onError(error, message) {
console.error(error, message);
},
});
broker.addStrategy(new Strategy(broker));
if (!broker.start()) {
console.error("Broker start failed");
process.exit(1);
}
//# sourceMappingURL=index.test.js.map