hft-js
Version:
High-Frequency Trading in Node.js
120 lines • 3.71 kB
JavaScript
/*
* tape.ts
*
* Copyright (c) 2025 Xiongfei Shi
*
* Author: Xiongfei Shi <xiongfei.shi(a)icloud.com>
* License: Apache-2.0
*
* https://github.com/shixiongfei/hft.js
*/
const calcTapeType = (volumeDelta, interestDelta) => {
if (interestDelta > 0) {
return volumeDelta === interestDelta ? "dual-open" : "open";
}
if (interestDelta < 0) {
return volumeDelta + interestDelta === 0 ? "dual-close" : "close";
}
if (volumeDelta > 0) {
return "turnover";
}
return "no-deal";
};
const calcTapeDirection = (tick, preTick) => {
const lastPrice = tick.lastPrice;
if (preTick) {
const preAskPrice1 = preTick.orderBook.asks.price[0] ?? Number.MAX_VALUE;
if (lastPrice >= preAskPrice1) {
return "up";
}
const preBidPrice1 = preTick.orderBook.bids.price[0] ?? Number.MIN_VALUE;
if (lastPrice <= preBidPrice1) {
return "down";
}
const askPrice1 = tick.orderBook.asks.price[0] ?? Number.MAX_VALUE;
if (lastPrice >= askPrice1) {
return "up";
}
const bidPrice1 = tick.orderBook.bids.price[0] ?? Number.MIN_VALUE;
if (lastPrice <= bidPrice1) {
return "down";
}
const prePrice = preTick.lastPrice;
if (lastPrice > prePrice) {
return "up";
}
if (lastPrice < prePrice) {
return "down";
}
if (bidPrice1 >= preAskPrice1) {
return "up";
}
if (askPrice1 <= preBidPrice1) {
return "down";
}
return "none";
}
else {
const askPrice1 = tick.orderBook.asks.price[0] ?? Number.MAX_VALUE;
if (lastPrice >= askPrice1) {
return "up";
}
const bidPrice1 = tick.orderBook.bids.price[0] ?? Number.MIN_VALUE;
if (lastPrice <= bidPrice1) {
return "down";
}
if (lastPrice > tick.preClose) {
return "up";
}
if (lastPrice < tick.preClose) {
return "down";
}
return "none";
}
};
const calcTapeStatus = (tapeType, tapeDirection) => {
if (tapeType === "open" && tapeDirection === "up") {
return "open-long";
}
if (tapeType === "open" && tapeDirection === "down") {
return "open-short";
}
if (tapeType === "close" && tapeDirection === "up") {
return "close-short";
}
if (tapeType === "close" && tapeDirection === "down") {
return "close-long";
}
if (tapeType === "turnover" && tapeDirection === "up") {
return "turnover-long";
}
if (tapeType === "turnover" && tapeDirection === "down") {
return "turnover-short";
}
if (tapeType === "dual-open") {
return "dual-open";
}
if (tapeType === "dual-close") {
return "dual-close";
}
return "invalid";
};
export const calcTapeData = (tick, preTick) => {
const volumeDelta = preTick ? tick.volume - preTick.volume : tick.volume;
const amountDelta = preTick ? tick.amount - preTick.amount : tick.amount;
const interestDelta = preTick
? tick.openInterest - preTick.openInterest
: tick.openInterest - tick.preOpenInterest;
const tapeType = calcTapeType(volumeDelta, interestDelta);
const tapeDirection = calcTapeDirection(tick, preTick);
const tapeStatus = calcTapeStatus(tapeType, tapeDirection);
return Object.freeze({
type: tapeType,
direction: tapeDirection,
status: tapeStatus,
interestDelta: interestDelta,
volumeDelta: volumeDelta,
amountDelta: amountDelta,
});
};
//# sourceMappingURL=tape.js.map