@thoshpathi/utils-smartapi-order
Version:
Utility functions for placing live and dummy orders using Angel One's SmartAPI, with helper methods for streamlined trading workflows.
206 lines (203 loc) • 6.74 kB
JavaScript
import {
OrderHelper
} from "./chunk-O6PJTRR5.mjs";
import {
delay,
toggleTrend
} from "./chunk-RQBWMBFA.mjs";
// src/helpers/live_order_helper.ts
import { groupByLatestMap } from "@thoshpathi/utils-core";
var LiveOrderHelper = class extends OrderHelper {
async handleScripsTrendReversal(scripTrendMapData) {
this.logger.d("run close open orders");
await this.closeTrendOpenOrders(scripTrendMapData);
this.logger.d("run place new orders");
await this.placeNewTrendOrders(scripTrendMapData);
}
async handleDaySquareoff() {
const openOrders = await this.getOpenOrders({});
if (openOrders == null) return;
return await this.processOrdersSquareoff(openOrders, "squareoff");
}
async processOrdersSquareoff(openOrders, status) {
const squareoffOrders = await this.generateCloseOrderParams(
openOrders,
status
);
if (squareoffOrders == null) return false;
await this.updateOrdersClose(squareoffOrders);
return true;
}
async handleOpenOrdersTracking() {
const orderCloseTracks = await this.getOrderCloseTrackDatas();
if (orderCloseTracks == null) return;
const completedOrderMap = await this.getCompletedOrderMap({
orders: orderCloseTracks.map((v) => v.order),
isOrderClosing: true
});
if (completedOrderMap == null) return;
const closeOrders = [];
for (const { order, status, ltp } of orderCloseTracks) {
const { id, symbol, candleInterval } = order;
const orderData = completedOrderMap.get(symbol);
if (orderData == null) continue;
closeOrders.push({
id,
symbol,
candleInterval,
exitOrderid: orderData.orderid,
exitPrice: orderData.price ?? orderData.averageprice ?? ltp,
status
});
}
if (closeOrders.length == 0) {
this.logger.w("closeOrders empty. no close track orders");
return;
}
await this.updateOrdersClose(closeOrders);
}
async closeTrendOpenOrders({
scripTrendMap
}) {
const names = Array.from(scripTrendMap.values()).map(
(v) => v.indexScrip.name
);
const openOrders = await this.getOpenOrders({ names });
if (openOrders == null) return;
const closeOrders = await this.generateCloseOrderParams(
openOrders,
"closed"
);
if (closeOrders == null) return false;
await this.updateOrdersClose(closeOrders);
return true;
}
async placeNewTrendOrders(scripTrendMapData) {
const newOrders = await this.getTrendNewOrders(scripTrendMapData);
if (newOrders == null) return;
const createNewOrders = await this.generateCreateNewOrders(newOrders);
if (createNewOrders == null) return;
await this.createOrders(createNewOrders, scripTrendMapData.candleInterval);
}
async generateCloseOrderParams(openOrders, status) {
const completedOrderMap = await this.getCompletedOrderMap({
orders: openOrders,
isOrderClosing: true
});
if (completedOrderMap == null) return;
const closeOrders = [];
for (const { id, symbol, candleInterval } of openOrders) {
const orderData = completedOrderMap.get(symbol);
if (orderData == null) continue;
const exitPrice = orderData.price ?? orderData.averageprice;
if (!exitPrice) {
this.logger.w(
symbol,
`[${orderData.orderid}]: price / avg.price empty`
);
continue;
}
closeOrders.push({
id,
symbol,
candleInterval,
exitOrderid: orderData.orderid,
exitPrice,
status
});
}
if (closeOrders.length == 0) {
this.logger.w(`closeOrders empty. no ${status} orders`);
return;
}
return closeOrders;
}
async generateCreateNewOrders(newOrders) {
const completedOrderMap = await this.getCompletedOrderMap({
orders: newOrders,
isOrderClosing: false
});
if (completedOrderMap == null) return;
const createNewOrders = [];
for (const order of newOrders) {
const completedOrder = completedOrderMap.get(order.symbol);
if (completedOrder == null) continue;
const { orderid, price, averageprice } = completedOrder;
order.entryOrderId = orderid;
order.entryPrice = price ?? averageprice ?? order.entryPrice;
createNewOrders.push(order);
}
if (createNewOrders.length == 0) {
this.logger.w("createNewOrders empty. no create orders");
return;
}
return createNewOrders;
}
/**
* Returns data of Map(symbol, OrderDetails) | undefined
*/
async getCompletedOrderMap(params) {
const { orders, isOrderClosing = false } = params;
const orderParams = orders.map((order) => {
const transactionType = isOrderClosing ? toggleTrend(order.transaction) : order.transaction;
return this.liveOrderParams({
symbol: order.symbol,
symbolToken: order.symbolToken,
exchange: order.exchange,
qty: order.qty,
transactionType
});
});
const completedOrders = await this.placeLiveOrders(orderParams);
if (completedOrders == null) return;
return groupByLatestMap(completedOrders, "tradingsymbol");
}
async placeLiveOrders(orderParams) {
try {
const buyPromises = orderParams.filter((v) => v.transactiontype === "BUY").map((params) => {
return this.smartapi.placeOrder_e(params);
});
const sellPromises = orderParams.filter((v) => v.transactiontype === "SELL").map((params) => {
return this.smartapi.placeOrder_e(params);
});
const responses = [];
if (buyPromises.length > 0) {
const buyResponses = await Promise.all(buyPromises);
responses.push(...buyResponses);
await delay(200);
}
if (sellPromises.length > 0) {
const sellResponses = await Promise.all(sellPromises);
responses.push(...sellResponses);
}
await delay(this.orderVerfiyWaitMs);
const completedOrders = await this.smartapi.fetchCompletedOrders(
responses
);
if (completedOrders == null || completedOrders.length == 0) {
this.logger.e("completedOrders empty. place order failed");
return;
}
return completedOrders;
} catch (error) {
this.logger.c("place live orders error", error);
}
return;
}
liveOrderParams(params) {
return {
tradingsymbol: params.symbol,
symboltoken: params.symbolToken,
exchange: params.exchange,
transactiontype: params.transactionType,
quantity: params.qty,
producttype: params.productType ?? "INTRADAY",
duration: params.duration ?? "DAY",
variety: "NORMAL",
ordertype: "MARKET"
};
}
};
export {
LiveOrderHelper
};