From d5849d2c9d3a6a41ae0b8cfec95cd0a52b496789 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Fri, 22 Oct 2021 17:15:20 +0530 Subject: [PATCH 01/16] ft: auto square off v2 --- lib/browserUtils.ts | 7 +- lib/exit-strategies/autoSquareOff.ts | 27 ++- .../individualLegExitOrders.ts | 50 +++-- .../minXPercentOrSupertrend.ts | 45 ++-- .../optionEntryWatcher.js | 8 +- .../optionSellerStrategy/optionSLWatcher.js | 13 +- lib/queue-processor/tradingQueue.ts | 22 -- lib/queue.ts | 22 +- lib/strategies/atmStraddle.ts | 53 +++-- lib/strategies/directionalOptionSelling.ts | 20 +- lib/utils.ts | 37 ++- lib/watchers/sllWatcher.ts | 17 +- lib/watchers/slmWatcher.ts | 211 ------------------ pages/api/order_history.js | 6 +- types/misc.ts | 5 + types/plans.ts | 2 +- types/trade.ts | 2 +- 17 files changed, 188 insertions(+), 359 deletions(-) delete mode 100644 lib/watchers/slmWatcher.ts diff --git a/lib/browserUtils.ts b/lib/browserUtils.ts index 0152c2db..ac5b2188 100644 --- a/lib/browserUtils.ts +++ b/lib/browserUtils.ts @@ -85,7 +85,6 @@ export function commonOnChangeHandler ( const getSchedulingApiProps = ({ isAutoSquareOffEnabled, squareOffTime, - exitStrategy, runAt, runNow, expireIfUnsuccessfulInMins @@ -97,9 +96,7 @@ const getSchedulingApiProps = ({ .format(), autoSquareOffProps: isAutoSquareOffEnabled ? { - time: squareOffTime, - deletePendingOrders: - exitStrategy !== EXIT_STRATEGIES.MULTI_LEG_PREMIUM_THRESHOLD + time: squareOffTime } : undefined, expiresAt: expireIfUnsuccessfulInMins @@ -189,7 +186,6 @@ export const formatFormDataForApi = ({ ...getSchedulingApiProps({ isAutoSquareOffEnabled, squareOffTime, - exitStrategy, expireIfUnsuccessfulInMins, runAt, runNow @@ -231,7 +227,6 @@ export const formatFormDataForApi = ({ ...getSchedulingApiProps({ isAutoSquareOffEnabled, squareOffTime, - exitStrategy, expireIfUnsuccessfulInMins, runAt, runNow diff --git a/lib/exit-strategies/autoSquareOff.ts b/lib/exit-strategies/autoSquareOff.ts index 49ac46cd..82b7c853 100644 --- a/lib/exit-strategies/autoSquareOff.ts +++ b/lib/exit-strategies/autoSquareOff.ts @@ -1,4 +1,5 @@ import { KiteOrder } from '../../types/kite' +import { ASO_TYPE } from '../../types/misc' import { ATM_STRADDLE_TRADE, ATM_STRANGLE_TRADE, @@ -7,6 +8,7 @@ import { import { USER_OVERRIDE } from '../constants' import console from '../logging' import { + convertSllToMarketOrder, // logDeep, patchDbTrade, remoteOrderSuccessEnsurer, @@ -122,29 +124,36 @@ export async function doSquareOffPositions ( } async function autoSquareOffStrat ({ + squareOffType, rawKiteOrdersResponse, - deletePendingOrders, initialJobData }: { + squareOffType: ASO_TYPE rawKiteOrdersResponse: KiteOrder[] - deletePendingOrders: boolean initialJobData: SUPPORTED_TRADE_CONFIG }): Promise { const { user } = initialJobData const kite = syncGetKiteInstance(user) - const completedOrders = rawKiteOrdersResponse - - if (deletePendingOrders) { - // console.log('deletePendingOrders init') + if (squareOffType === ASO_TYPE.SLL_TO_MARKET) { + const triggerPendingOrders = rawKiteOrdersResponse + // if completed orders exist, they can be converted to market hours try { - await doDeletePendingOrders(completedOrders, kite) - // console.log('🟢 deletePendingOrders success', res) + await Promise.all( + triggerPendingOrders.map(order => convertSllToMarketOrder(kite, order)) + ) } catch (e) { console.log('🔴 deletePendingOrders failed') console.error(e) } + } else { + const completedOrders = rawKiteOrdersResponse + try { + await doSquareOffPositions(completedOrders, kite, initialJobData) + } catch (e) { + console.log('🔴 doSquareOffPositions failed') + console.error(e) + } } - return doSquareOffPositions(completedOrders, kite, initialJobData) } export default autoSquareOffStrat diff --git a/lib/exit-strategies/individualLegExitOrders.ts b/lib/exit-strategies/individualLegExitOrders.ts index 1206ed02..0dd2adfb 100644 --- a/lib/exit-strategies/individualLegExitOrders.ts +++ b/lib/exit-strategies/individualLegExitOrders.ts @@ -1,12 +1,17 @@ import { KiteOrder } from '../../types/kite' +import { ASO_TYPE } from '../../types/misc' import { SL_ORDER_TYPE } from '../../types/plans' import { SUPPORTED_TRADE_CONFIG } from '../../types/trade' import console from '../logging' -import { addToNextQueue, WATCHER_Q_NAME } from '../queue' -import orderResponse from '../strategies/mockData/orderResponse' +import { + addToAutoSquareOffQueue, + addToNextQueue, + WATCHER_Q_NAME +} from '../queue' +// import orderResponse from '../strategies/mockData/orderResponse' import { attemptBrokerOrders, - isUntestedFeaturesEnabled, + // isUntestedFeaturesEnabled, remoteOrderSuccessEnsurer, round, syncGetKiteInstance @@ -62,10 +67,10 @@ async function individualLegExitOrders ({ orderTag, rollback, slLimitPricePercent = 1, - instrument + instrument, + isAutoSquareOffEnabled } = initialJobData - const slOrderType = SL_ORDER_TYPE.SLL const kite = _kite || syncGetKiteInstance(user) const exitOrders = completedOrders.map(order => { @@ -103,10 +108,7 @@ async function individualLegExitOrders ({ exchange } - if (slOrderType === SL_ORDER_TYPE.SLL) { - exitOrder = convertSlmToSll(exitOrder, slLimitPricePercent!, kite) - } - + exitOrder = convertSlmToSll(exitOrder, slLimitPricePercent!, kite) exitOrder.trigger_price = round(exitOrder.trigger_price!) console.log('placing exit orders...', exitOrder) return exitOrder @@ -132,20 +134,26 @@ async function individualLegExitOrders ({ throw Error('rolled back onBrokenExitOrders') } - if (slOrderType === SL_ORDER_TYPE.SLL) { - const watcherQueueJobs = statefulOrders.map(async exitOrder => { - return addToNextQueue(initialJobData, { - _nextTradingQueue: WATCHER_Q_NAME, - rawKiteOrderResponse: exitOrder - }) + if (isAutoSquareOffEnabled) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.SLL_TO_MARKET, + jobResponse: { rawKiteOrdersResponse: statefulOrders }, + initialJobData + }) + } + + const watcherQueueJobs = statefulOrders.map(async exitOrder => { + return addToNextQueue(initialJobData, { + _nextTradingQueue: WATCHER_Q_NAME, + rawKiteOrderResponse: exitOrder }) + }) - try { - await Promise.all(watcherQueueJobs) - } catch (e) { - console.log('error adding to `watcherQueueJobs`') - console.log(e.message ? e.message : e) - } + try { + await Promise.all(watcherQueueJobs) + } catch (e) { + console.log('error adding to `watcherQueueJobs`') + console.log(e.message ? e.message : e) } return statefulOrders diff --git a/lib/exit-strategies/minXPercentOrSupertrend.ts b/lib/exit-strategies/minXPercentOrSupertrend.ts index 0d37ab3f..2919e38c 100644 --- a/lib/exit-strategies/minXPercentOrSupertrend.ts +++ b/lib/exit-strategies/minXPercentOrSupertrend.ts @@ -1,7 +1,6 @@ import axios from 'axios' import dayjs from 'dayjs' import { KiteOrder } from '../../types/kite' -import { SL_ORDER_TYPE } from '../../types/plans' import { DIRECTIONAL_OPTION_SELLING_TRADE } from '../../types/trade' import console from '../logging' @@ -10,6 +9,7 @@ import { attemptBrokerOrders, getLastOpenDateSince, getNearestCandleTime, + getOrderHistory, getPercentageChange, logDeep, remoteOrderSuccessEnsurer, @@ -35,15 +35,14 @@ async function minXPercentOrSupertrend ({ hedgeOrderResponse }: DOS_TRAILING_INTERFACE): Promise { const { user, orderTag, slLimitPricePercent = 1, instrument } = initialJobData - const slOrderType = SL_ORDER_TYPE.SLL try { const kite = syncGetKiteInstance(user) const [rawKiteOrderResponse] = rawKiteOrdersResponse // NB: rawKiteOrderResponse here is of pending SLM Order - const orderHistory: KiteOrder[] = await withRemoteRetry(() => - kite.getOrderHistory(rawKiteOrderResponse.order_id) + const byRecencyOrderHistory: KiteOrder[] = await getOrderHistory( + kite, + rawKiteOrderResponse.order_id! ) - const byRecencyOrderHistory = orderHistory.reverse() const isSlOrderCancelled = byRecencyOrderHistory.find( odr => odr.status === 'CANCELLED' @@ -126,28 +125,21 @@ async function minXPercentOrSupertrend ({ // console.log('should trail SL!') try { - const sllOrderProps = - slOrderType === SL_ORDER_TYPE.SLL - ? convertSlmToSll( - { - transaction_type: kite.TRANSACTION_TYPE_BUY, - trigger_price: newSL - } as KiteOrder, - slLimitPricePercent!, - kite - ) - : null + const sllOrderProps = convertSlmToSll( + { + transaction_type: kite.TRANSACTION_TYPE_BUY, + trigger_price: newSL + } as KiteOrder, + slLimitPricePercent!, + kite + ) const res = await kite.modifyOrder( triggerPendingOrder!.variety, triggerPendingOrder!.order_id, - slOrderType === SL_ORDER_TYPE.SLL - ? { - trigger_price: sllOrderProps!.trigger_price, - price: sllOrderProps!.price - } - : { - trigger_price: newSL - } + { + trigger_price: sllOrderProps!.trigger_price, + price: sllOrderProps!.price + } ) console.log( `🟢 [minXPercentOrSupertrend] SL modified from ${String( @@ -175,10 +167,7 @@ async function minXPercentOrSupertrend ({ tag: orderTag! } - if (slOrderType === SL_ORDER_TYPE.SLL) { - exitOrder = convertSlmToSll(exitOrder, slLimitPricePercent!, kite) - } - + exitOrder = convertSlmToSll(exitOrder, slLimitPricePercent!, kite) const remoteOrder = remoteOrderSuccessEnsurer({ ensureOrderState: 'TRIGGER PENDING', instrument, diff --git a/lib/queue-processor/optionSellerStrategy/optionEntryWatcher.js b/lib/queue-processor/optionSellerStrategy/optionEntryWatcher.js index cfe5f22a..2d905a39 100644 --- a/lib/queue-processor/optionSellerStrategy/optionEntryWatcher.js +++ b/lib/queue-processor/optionSellerStrategy/optionEntryWatcher.js @@ -1,5 +1,6 @@ import { INSTRUMENT_DETAILS } from '../../constants' import { + getCompletedOrderFromOrderHistoryById, getIndexInstruments, getInstrumentPrice, getTradingSymbolsByOptionPrice, @@ -20,10 +21,9 @@ const optionSellerEntryWatcher = async ({ try { const { user, orderTag, instrument } = initialJobData const kite = syncGetKiteInstance(user) - const orderHistory = await kite.getOrderHistory(limitOrderAckId) - const revOrderHistory = orderHistory.reverse() - const completedOrder = revOrderHistory.find( - order => order.status === kite.STATUS_COMPLETE + const completedOrder = await getCompletedOrderFromOrderHistoryById( + kite, + limitOrderAckId ) if (!completedOrder) { return Promise.reject( diff --git a/lib/queue-processor/optionSellerStrategy/optionSLWatcher.js b/lib/queue-processor/optionSellerStrategy/optionSLWatcher.js index 3ad7806d..dc30f190 100644 --- a/lib/queue-processor/optionSellerStrategy/optionSLWatcher.js +++ b/lib/queue-processor/optionSellerStrategy/optionSLWatcher.js @@ -1,4 +1,8 @@ -import { syncGetKiteInstance } from '../../utils' +import { + getCompletedOrderFromOrderHistoryById, + getOrderHistory, + syncGetKiteInstance +} from '../../utils' import console from '../../logging' @@ -14,10 +18,9 @@ const optionSellerSLWatcher = async ({ try { const { user, orderTag } = initialJobData const kite = syncGetKiteInstance(user) - const orderHistory = await kite.getOrderHistory(slOrderAckId) - const revOrderHistory = orderHistory.reverse() - const completedOrder = revOrderHistory.find( - order => order.status === kite.STATUS_COMPLETE + const completedOrder = await getCompletedOrderFromOrderHistoryById( + kite, + slOrderAckId ) if (!completedOrder) { return Promise.reject(new Error('[optionSellerSLWatcher] still pending!')) diff --git a/lib/queue-processor/tradingQueue.ts b/lib/queue-processor/tradingQueue.ts index eeed26f2..0420b525 100644 --- a/lib/queue-processor/tradingQueue.ts +++ b/lib/queue-processor/tradingQueue.ts @@ -4,7 +4,6 @@ import { Job, Worker } from 'bullmq' import { ANCILLARY_TASKS, STRATEGIES } from '../constants' import console from '../logging' import { - addToAutoSquareOffQueue, addToNextQueue, ANCILLARY_Q_NAME, redisConnection, @@ -64,27 +63,6 @@ const worker = new Worker( } catch (e) { console.log('[error] enabling orderbook sync by tag...', e) } - - const { isAutoSquareOffEnabled, strategy } = job.data - // can't enable auto square off for DOS - // because we don't know upfront how many orders would get punched - if ( - strategy !== STRATEGIES.DIRECTIONAL_OPTION_SELLING && - isAutoSquareOffEnabled - ) { - try { - // console.log('enabling auto square off...') - const asoResponse = await addToAutoSquareOffQueue({ - //eslint-disable-line - initialJobData: job.data, - jobResponse: result - }) - // const { data, name } = asoResponse - // console.log('🟢 success enable auto square off', { data, name }) - } catch (e) { - console.log('🔴 failed to enable auto square off', e) - } - } return result }, { diff --git a/lib/queue.ts b/lib/queue.ts index c65ad9fa..762f3ae7 100644 --- a/lib/queue.ts +++ b/lib/queue.ts @@ -2,6 +2,9 @@ import { Queue, QueueScheduler, JobsOptions, Job } from 'bullmq' import dayjs from 'dayjs' import IORedis from 'ioredis' import { v4 as uuidv4 } from 'uuid' +import { KiteOrder } from '../types/kite' +import { ASO_TYPE } from '../types/misc' +import { SUPPORTED_TRADE_CONFIG } from '../types/trade' import console from './logging' import { @@ -165,12 +168,19 @@ export async function addToNextQueue ( } export async function addToAutoSquareOffQueue ({ + squareOffType, initialJobData, jobResponse -}) { - const { - autoSquareOffProps: { time, deletePendingOrders } - } = initialJobData +}: { + squareOffType: ASO_TYPE + jobResponse: { + rawKiteOrdersResponse: KiteOrder[] + squareOffOrders?: KiteOrder[] + } + initialJobData: SUPPORTED_TRADE_CONFIG +}): Promise { + const { autoSquareOffProps } = initialJobData + const { time } = autoSquareOffProps as { time: string } const { rawKiteOrdersResponse, squareOffOrders } = jobResponse const finalOrderTime = getMisOrderLastSquareOffTime() const runAtTime = isMockOrder() @@ -184,8 +194,8 @@ export async function addToAutoSquareOffQueue ({ return autoSquareOffQueue.add( `${AUTO_SQUARE_OFF_Q_NAME}_${uuidv4() as string}`, { + squareOffType, rawKiteOrdersResponse: squareOffOrders || rawKiteOrdersResponse, - deletePendingOrders, initialJobData }, { @@ -194,5 +204,5 @@ export async function addToAutoSquareOffQueue ({ ) } -export const cleanupQueues = async () => +export const cleanupQueues = async (): Promise => await Promise.all(allQueues.map(async queue => await queue.obliterate())) diff --git a/lib/strategies/atmStraddle.ts b/lib/strategies/atmStraddle.ts index 294806e4..e06405c7 100644 --- a/lib/strategies/atmStraddle.ts +++ b/lib/strategies/atmStraddle.ts @@ -1,6 +1,6 @@ import dayjs, { ConfigType } from 'dayjs' import { KiteOrder } from '../../types/kite' -import { SignalXUser } from '../../types/misc' +import { SignalXUser, ASO_TYPE } from '../../types/misc' import { ATM_STRADDLE_TRADE } from '../../types/trade' import { @@ -11,7 +11,7 @@ import { } from '../constants' import { doSquareOffPositions } from '../exit-strategies/autoSquareOff' import console from '../logging' -import { EXIT_TRADING_Q_NAME } from '../queue' +import { EXIT_TRADING_Q_NAME, addToAutoSquareOffQueue } from '../queue' import { attemptBrokerOrders, delay, @@ -190,23 +190,9 @@ export const createOrder = ({ } } -async function atmStraddle ({ - _kite, - instrument, - lots, - user, - expiresAt, - orderTag, - rollback, - maxSkewPercent, - thresholdSkewPercent, - takeTradeIrrespectiveSkew, - isHedgeEnabled, - hedgeDistance, - productType = PRODUCT_TYPE.MIS, - volatilityType = VOLATILITY_TYPE.SHORT, - _nextTradingQueue = EXIT_TRADING_Q_NAME -}: ATM_STRADDLE_TRADE): Promise< +async function atmStraddle ( + jobData: ATM_STRADDLE_TRADE +): Promise< | { _nextTradingQueue: string straddle: Record @@ -215,6 +201,24 @@ async function atmStraddle ({ } | undefined > { + const { + _kite, + instrument, + lots, + user, + expiresAt, + orderTag, + rollback, + maxSkewPercent, + thresholdSkewPercent, + takeTradeIrrespectiveSkew, + isAutoSquareOffEnabled, + isHedgeEnabled, + hedgeDistance, + productType = PRODUCT_TYPE.MIS, + volatilityType = VOLATILITY_TYPE.SHORT, + _nextTradingQueue = EXIT_TRADING_Q_NAME + } = jobData const kite = _kite || syncGetKiteInstance(user) const { @@ -247,6 +251,7 @@ async function atmStraddle ({ let allOrdersLocal: KiteOrder[] = [] let hedgeOrdersLocal: KiteOrder[] = [] + let hedgeOrders: KiteOrder[] = [] let allOrders: KiteOrder[] = [] if (volatilityType === VOLATILITY_TYPE.SHORT && isHedgeEnabled) { @@ -318,6 +323,7 @@ async function atmStraddle ({ throw Error('rolled back onBrokenHedgeOrders') } + hedgeOrders = [...statefulOrders] allOrders = [...statefulOrders] } @@ -341,6 +347,15 @@ async function atmStraddle ({ throw Error('rolled back on onBrokenPrimaryOrders') } + // all hedges are enabled, turn on auto square off on those positions + if (isAutoSquareOffEnabled && hedgeOrders.length) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, + jobResponse: { rawKiteOrdersResponse: hedgeOrders }, + initialJobData: jobData + }) + } + return { _nextTradingQueue, straddle, diff --git a/lib/strategies/directionalOptionSelling.ts b/lib/strategies/directionalOptionSelling.ts index 851fecce..f016102f 100644 --- a/lib/strategies/directionalOptionSelling.ts +++ b/lib/strategies/directionalOptionSelling.ts @@ -36,6 +36,7 @@ import { withRemoteRetry, logDeep } from '../utils' +import { ASO_TYPE } from '../../types/misc' const SIGNALX_URL = process.env.SIGNALX_URL ?? 'https://indicator.signalx.trade' @@ -430,16 +431,25 @@ async function punchOrders ( ].filter(o => o) if (isAutoSquareOffEnabled) { try { - const asoResponse = await addToAutoSquareOffQueue({ + if (hedgeOrdersResponse.length) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, + initialJobData: nextQueueData, + jobResponse: { + rawKiteOrdersResponse: hedgeOrdersResponse + } + }) + } + + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.SLL_TO_MARKET, initialJobData: nextQueueData, jobResponse: { - rawKiteOrdersResponse: allPunchedOrders + rawKiteOrdersResponse: exitOrders } }) - const { data, name } = asoResponse console.log( - '🟢 [directionalOptionSelling] success enable auto square off', - { data, name } + '🟢 [directionalOptionSelling] success enable auto square off' ) } catch (e) { console.log( diff --git a/lib/utils.ts b/lib/utils.ts index 919778d7..8c881065 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -202,8 +202,19 @@ export function syncGetKiteInstance (user) { }) } -export async function getCompletedOrderFromOrderHistoryById (kite, orderId) { - const orders = await kite.getOrderHistory(orderId) +export async function getOrderHistory ( + kite: any, + orderId: string +): Promise { + const history = await withRemoteRetry(() => kite.getOrderHistory(orderId)) + return [...history].reverse() +} + +export async function getCompletedOrderFromOrderHistoryById ( + kite: any, + orderId: string +): Promise { + const orders = await getOrderHistory(kite, orderId) return orders.find(odr => odr.status === 'COMPLETE') } @@ -787,10 +798,7 @@ export const orderStateChecker = (kite, orderId, ensureOrderState) => { return false } try { - const orderHistory = await withRemoteRetry(() => - kite.getOrderHistory(orderId) - ) - const byRecencyOrderHistory = orderHistory.reverse() + const byRecencyOrderHistory = await getOrderHistory(kite, orderId) // if it reaches here, then order exists in broker system const expectedStateOrder = byRecencyOrderHistory.find( @@ -805,7 +813,6 @@ export const orderStateChecker = (kite, orderId, ensureOrderState) => { orderId, ensureOrderState }) - logDeep(orderHistory) const wasOrderRejectedOrCancelled = byRecencyOrderHistory.find( odr => @@ -1224,3 +1231,19 @@ export function round (value: number, step = 0.5): number { const inv = 1.0 / step return Math.round(value * inv) / inv } + +export const convertSllToMarketOrder = async ( + kite: any, + order: KiteOrder +): Promise => { + // ensure order is not in complete state + const completedOrder = await getOrderHistory(kite, order.order_id!) + if (completedOrder) { + return + } + return withRemoteRetry(() => + kite.modifyOrder(order.variety, order.order_id, { + order_type: kite.ORDER_TYPE_MARKET + }) + ) +} diff --git a/lib/watchers/sllWatcher.ts b/lib/watchers/sllWatcher.ts index 5962ce0c..0249c48b 100644 --- a/lib/watchers/sllWatcher.ts +++ b/lib/watchers/sllWatcher.ts @@ -12,11 +12,12 @@ import { Promise } from 'bluebird' import { SignalXUser } from '../../types/misc' import console from '../logging' import { + convertSllToMarketOrder, finiteStateChecker, + getOrderHistory, ms, orderStateChecker, - syncGetKiteInstance, - withRemoteRetry + syncGetKiteInstance } from '../utils' const sllWatcher = async ({ @@ -28,9 +29,7 @@ const sllWatcher = async ({ }) => { try { const kite = syncGetKiteInstance(user) - const orderHistory = ( - await withRemoteRetry(() => kite.getOrderHistory(sllOrderId)) - ).reverse() + const orderHistory = await getOrderHistory(kite, sllOrderId) const isOrderCompleted = orderHistory.find( order => order.status === kite.STATUS_COMPLETE ) @@ -39,7 +38,7 @@ const sllWatcher = async ({ } const cancelledOrder = orderHistory.find(order => - order.status.includes(kite.STATUS_CANCELLED) + order.status!.includes(kite.STATUS_CANCELLED) ) if (cancelledOrder) { @@ -71,11 +70,7 @@ const sllWatcher = async ({ sllOrderId ) try { - await withRemoteRetry(() => - kite.modifyOrder(openOrder.variety, sllOrderId, { - order_type: kite.ORDER_TYPE_MARKET - }) - ) + await convertSllToMarketOrder(kite, openOrder) return Promise.resolve( `🟢 [sllWatcher] squared off open SLL order id ${sllOrderId}` ) diff --git a/lib/watchers/slmWatcher.ts b/lib/watchers/slmWatcher.ts deleted file mode 100644 index 5c61981b..00000000 --- a/lib/watchers/slmWatcher.ts +++ /dev/null @@ -1,211 +0,0 @@ -/** - * what happens - Exchange cancels orders that lie outside execution range - * - * 1. SLM order can be partially filled before it gets cancelled - * 2. Entire order can be cancelled - * - * Action plan: - * - * 1. Have a reference to the order id created by zerodha - * 2. Every 5 seconds - * 2. SLM order is in state `CANCELLED` or `COMPLETED` - * 3. Cancel checker if `COMPLETED` - * 4. Square off open position qty that was managed by this order_id - * 5. If `Cancelled`, get the order history of this order_id, - * 1. Get the item with status Cancelled. - * 2. Fetch its cancelled_quantity - * 3. Place a market exit order for cancelled_quantity for the tradingsymbol - * 4. Add this new order back to this queue for monitoring - * - */ - -import { KiteOrder } from '../../types/kite' -import { SignalXUser } from '../../types/misc' -import { SUPPORTED_TRADE_CONFIG } from '../../types/trade' -import console from '../logging' -import { addToNextQueue, WATCHER_Q_NAME } from '../queue' -import { - getInstrumentPrice, - remoteOrderSuccessEnsurer, - syncGetKiteInstance, - withRemoteRetry -} from '../utils' - -/** - * [NB] IMPORTANT! - * WATCH_MANUAL_CANCELLED_ORDERS is for testing this only! - * DO NOT enable this env variable on your account! - * e.g. in DOS, Khaching can itself cancel a pending order and create a new SLM order - * if you were to enable this, - * the position will get auto squared off as soon as Khaching cancels that pending order - */ -const WATCH_MANUAL_CANCELLED_ORDERS = process.env.WATCH_MANUAL_CANCELLED_ORDERS - ? JSON.parse(process.env.WATCH_MANUAL_CANCELLED_ORDERS) - : false - -const slmWatcher = async ({ - slmOrderId, - user, - originalTriggerPrice, - _queueJobData -}: { - slmOrderId: string - user: SignalXUser - originalTriggerPrice: number - _queueJobData: { initialJobData: SUPPORTED_TRADE_CONFIG } -}) => { - /** - * Scenario for the need of `originalTriggerPrice` - * - consider the initial SLM order gets cancelled at 50 - * - watcher sees new LTP to be 51 - * - watcher places `market` exit order, but order gets rejected - * - now the ref to slmOrderId will contain no triggerPrice as it was a market order - * - * - * hence - - * - we'll need to pass through the original trigger price down the rabbit hole - */ - try { - const kite = syncGetKiteInstance(user) - const orderHistory = ( - await withRemoteRetry(() => kite.getOrderHistory(slmOrderId)) - ).reverse() - const isOrderCompleted = orderHistory.find( - order => order.status === kite.STATUS_COMPLETE - ) - if (isOrderCompleted) { - return Promise.resolve('[slmWatcher] order COMPLETED!') - } - - const cancelledOrder = orderHistory.find(order => - order.status.includes(kite.STATUS_CANCELLED) - ) - - if (!cancelledOrder) { - return Promise.reject( - new Error('[slmWatcher] neither COMPLETED nor CANCELLED. Watching!') - ) - } - - const { - cancelled_quantity: cancelledQty, - status_message_raw: statusMessageRaw, - transaction_type: transactionType, - trigger_price: cancelledTriggerPrice, - tradingsymbol, - exchange, - product - } = cancelledOrder - - const triggerPrice = originalTriggerPrice || cancelledTriggerPrice - - /** - * Conditions: - * 1. WATCH_MANUAL_CANCELLED_ORDERS = false && statusMessageRaw = null - * true && true - returned - * - * 2. WATCH_MANUAL_CANCELLED_ORDERS = false && statusMessageRaw = '17070' - * true && false - continue - * - * 3. WATCH_MANUAL_CANCELLED_ORDERS = true && statusMessageRaw = null - * false && true - continue - * - * 4. WATCH_MANUAL_CANCELLED_ORDERS = true && statusMessageRaw = '17070' - * false && false - continue - */ - - if ( - !WATCH_MANUAL_CANCELLED_ORDERS && - statusMessageRaw !== - '17070 : The Price is out of the current execution range' - ) { - return Promise.resolve('[slmWatcher] order cancelled by user!') - } - - console.log('🟢 [slmWatcher] found cancelled SLM order!', { - slmOrderId, - cancelledQty, - statusMessageRaw - }) - - if (!cancelledQty) { - return Promise.resolve('[slmWatcher] no cancelled qty!') - } - - const positions = await withRemoteRetry(() => kite.getPositions()) - - const { net } = positions - const openPositionThatMustBeSquaredOff = net.find( - position => - position.tradingsymbol === tradingsymbol && - position.product === product && - position.exchange === exchange && - Math.abs(position.quantity) >= cancelledQty - ) - - if (!openPositionThatMustBeSquaredOff) { - return Promise.resolve('[slmWatcher] no open position to be squared off!') - } - - console.log( - '[slmWatcher] openPositionThatMustBeSquaredOff', - openPositionThatMustBeSquaredOff - ) - - const ltp = await withRemoteRetry(async () => - getInstrumentPrice(kite, tradingsymbol, exchange) - ) - - const newOrderType = - (transactionType === kite.TRANSACTION_TYPE_BUY && ltp < triggerPrice) || - (transactionType === kite.TRANSACTION_TYPE_SELL && ltp > triggerPrice) - ? kite.ORDER_TYPE_SLM - : kite.ORDER_TYPE_MARKET - - const exitOrder: KiteOrder = { - tradingsymbol, - exchange, - product, - quantity: cancelledQty, - transaction_type: transactionType, - order_type: newOrderType, - tag: _queueJobData.initialJobData.orderTag! - } - - if (newOrderType === kite.ORDER_TYPE_SLM) { - exitOrder.trigger_price = triggerPrice - } - - console.log('[slmWatcher] placing exit order', exitOrder) - try { - const { response } = await remoteOrderSuccessEnsurer({ - ensureOrderState: exitOrder.trigger_price - ? 'TRIGGER PENDING' - : kite.STATUS_COMPLETE, - orderProps: exitOrder, - instrument: _queueJobData.initialJobData.instrument, - user - }) - // add this new job to the watcher queue and ensure it succeeds - await addToNextQueue(_queueJobData.initialJobData, { - _nextTradingQueue: WATCHER_Q_NAME, - rawKiteOrderResponse: response, - originalTriggerPrice: triggerPrice - }) - } catch (e) { - console.log( - '[slmWatcher] error adding watcher for new exit market order', - e - ) - } - return Promise.resolve('[slmWatcher] placing exit order') - } catch (e) { - console.log('🔴 [slmWatcher] error. Checker terminated!!', e) - // a promise reject here could be dangerous due to retry logic. - // It could lead to multiple exit orders for the same initial order_id - // hence, resolve - return Promise.resolve('[slmWatcher] error') - } -} - -export default slmWatcher diff --git a/pages/api/order_history.js b/pages/api/order_history.js index 9cfb3581..113a4d47 100644 --- a/pages/api/order_history.js +++ b/pages/api/order_history.js @@ -1,5 +1,5 @@ import withSession from '../../lib/session' -import { syncGetKiteInstance } from '../../lib/utils' +import { getOrderHistory, syncGetKiteInstance } from '../../lib/utils' export default withSession(async (req, res) => { const user = req.session.get('user') @@ -12,8 +12,8 @@ export default withSession(async (req, res) => { const { id: orderId } = req.query - const orderHistory = await kite.getOrderHistory(orderId) - res.json(orderHistory.reverse()) + const orderHistory = await getOrderHistory(kite, orderId) + res.json(orderHistory) }) // 210428200252388 diff --git a/types/misc.ts b/types/misc.ts index 3636be68..59131f28 100644 --- a/types/misc.ts +++ b/types/misc.ts @@ -31,3 +31,8 @@ export interface DBMeta { _createdOn?: string _updatedOn?: string } + +export enum ASO_TYPE { + OPEN_POSITION_SQUARE_OFF = 'OPEN_POSITION_SQUARE_OFF', + SLL_TO_MARKET = 'SLL_TO_MARKET' +} diff --git a/types/plans.ts b/types/plans.ts index c857ec18..85cb1a62 100644 --- a/types/plans.ts +++ b/types/plans.ts @@ -19,7 +19,7 @@ export interface SavedPlanMeta extends COMMON_TRADE_PROPS { // _collection?: DailyPlansDayKey isAutoSquareOffEnabled: boolean runNow?: boolean - autoSquareOffProps?: { time: string; deletePendingOrders: boolean } + autoSquareOffProps?: { time: string } runAt?: string squareOffTime: string | undefined expiresAt?: string diff --git a/types/trade.ts b/types/trade.ts index b9b1392f..52ecdd04 100644 --- a/types/trade.ts +++ b/types/trade.ts @@ -12,7 +12,7 @@ export interface TradeMeta extends DBMeta { runNow?: boolean runAt?: string squareOffTime: string | undefined - autoSquareOffProps?: { time: string; deletePendingOrders: boolean } + autoSquareOffProps?: { time: string } expiresAt?: string _kite?: unknown // this is only used in jest for unit tests user?: SignalXUser // this is only available once job has been created on server From 199576b4110198c6e2c309ba8d78a026c0b0589f Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 15 Nov 2021 14:44:37 +0530 Subject: [PATCH 02/16] fx: fix multi leg square off issues --- lib/queue.ts | 19 ++++++++++++------ lib/strategies/atmStraddle.ts | 28 +++++++++++++++++++------- lib/strategies/strangle.ts | 37 ++++++++++++++++++++++++++++++----- lib/utils.ts | 3 ++- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/lib/queue.ts b/lib/queue.ts index 762f3ae7..1b02de3e 100644 --- a/lib/queue.ts +++ b/lib/queue.ts @@ -14,6 +14,7 @@ import { getQueueOptionsForExitStrategy, getTimeLeftInMarketClosingMs, isMockOrder, + logDeep, ms } from './utils' @@ -190,14 +191,20 @@ export async function addToAutoSquareOffQueue ({ : time const delay = dayjs(runAtTime).diff(dayjs()) - // console.log(`>>> auto square off scheduled for ${Math.ceil(delay / 60000)} minutes from now`) + console.log( + `>>> auto square off scheduled for ${Math.ceil( + delay / 60000 + )} minutes from now` + ) + const queueProps = { + squareOffType, + rawKiteOrdersResponse: squareOffOrders || rawKiteOrdersResponse, + initialJobData + } + logDeep(queueProps) return autoSquareOffQueue.add( `${AUTO_SQUARE_OFF_Q_NAME}_${uuidv4() as string}`, - { - squareOffType, - rawKiteOrdersResponse: squareOffOrders || rawKiteOrdersResponse, - initialJobData - }, + queueProps, { delay } diff --git a/lib/strategies/atmStraddle.ts b/lib/strategies/atmStraddle.ts index c9f10282..c24bcf84 100644 --- a/lib/strategies/atmStraddle.ts +++ b/lib/strategies/atmStraddle.ts @@ -5,6 +5,7 @@ import { ATM_STRADDLE_TRADE } from '../../types/trade' import { EXPIRY_TYPE, + EXIT_STRATEGIES, INSTRUMENT_DETAILS, INSTRUMENT_PROPERTIES, PRODUCT_TYPE, @@ -218,6 +219,7 @@ async function atmStraddle ( isAutoSquareOffEnabled, isHedgeEnabled, hedgeDistance, + exitStrategy, productType = PRODUCT_TYPE.MIS, volatilityType = VOLATILITY_TYPE.SHORT, expiryType = EXPIRY_TYPE.CURRENT, @@ -353,13 +355,25 @@ async function atmStraddle ( throw Error('rolled back on onBrokenPrimaryOrders') } - // all hedges are enabled, turn on auto square off on those positions - if (isAutoSquareOffEnabled && hedgeOrders.length) { - await addToAutoSquareOffQueue({ - squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, - jobResponse: { rawKiteOrdersResponse: hedgeOrders }, - initialJobData: jobData - }) + if (isAutoSquareOffEnabled) { + if (exitStrategy === EXIT_STRATEGIES.MULTI_LEG_PREMIUM_THRESHOLD) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, + jobResponse: { rawKiteOrdersResponse: allOrders }, + initialJobData: jobData + }) + } else { + // if hedges are enabled, + // turn on auto square off on those positions + // as they won't have SL orders + if (hedgeOrders.length) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, + jobResponse: { rawKiteOrdersResponse: hedgeOrders }, + initialJobData: jobData + }) + } + } } return { diff --git a/lib/strategies/strangle.ts b/lib/strategies/strangle.ts index dbdcf680..8bf68cee 100644 --- a/lib/strategies/strangle.ts +++ b/lib/strategies/strangle.ts @@ -6,10 +6,11 @@ import { INSTRUMENT_DETAILS, PRODUCT_TYPE, STRANGLE_ENTRY_STRATEGIES, - VOLATILITY_TYPE + VOLATILITY_TYPE, + EXIT_STRATEGIES } from '../constants' import console from '../logging' -import { EXIT_TRADING_Q_NAME } from '../queue' +import { addToAutoSquareOffQueue, EXIT_TRADING_Q_NAME } from '../queue' import { apiResponseObject, attemptBrokerOrders, @@ -28,6 +29,7 @@ import { doSquareOffPositions } from '../exit-strategies/autoSquareOff' import dayjs, { Dayjs } from 'dayjs' import { KiteOrder } from '../../types/kite' import axios from 'axios' +import { ASO_TYPE } from '../../types/misc' export const getNearestContractDate = async ( atmStrike: number, @@ -140,7 +142,7 @@ const getStrangleStrikes = async ({ } } -async function atmStrangle (args: ATM_STRANGLE_TRADE) { +async function atmStrangle (jobData: ATM_STRANGLE_TRADE) { try { const { instrument, @@ -157,8 +159,10 @@ async function atmStrangle (args: ATM_STRANGLE_TRADE) { productType = PRODUCT_TYPE.MIS, volatilityType = VOLATILITY_TYPE.SHORT, expiryType, + isAutoSquareOffEnabled, + exitStrategy, _nextTradingQueue = EXIT_TRADING_Q_NAME - } = args + } = jobData const { lotSize, nfoSymbol, @@ -170,7 +174,7 @@ async function atmStrangle (args: ATM_STRANGLE_TRADE) { const sourceData = await getIndexInstruments() const { atmStrike } = await getATMStrikes({ - ...args, + ...jobData, takeTradeIrrespectiveSkew: true, instrumentsData: sourceData, startTime: dayjs(), @@ -203,6 +207,7 @@ async function atmStrangle (args: ATM_STRANGLE_TRADE) { let allOrdersLocal: KiteOrder[] = [] let hedgeOrdersLocal: KiteOrder[] = [] + let hedgeOrders: KiteOrder[] = [] let allOrders: KiteOrder[] = [] if (volatilityType === VOLATILITY_TYPE.SHORT && isHedgeEnabled) { @@ -278,6 +283,7 @@ async function atmStrangle (args: ATM_STRANGLE_TRADE) { throw Error('rolled back onBrokenHedgeOrders') } + hedgeOrders = [...statefulOrders] allOrders = [...statefulOrders] } @@ -301,6 +307,27 @@ async function atmStrangle (args: ATM_STRANGLE_TRADE) { throw Error('rolled back on onBrokenPrimaryOrders') } + if (isAutoSquareOffEnabled) { + if (exitStrategy === EXIT_STRATEGIES.MULTI_LEG_PREMIUM_THRESHOLD) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, + jobResponse: { rawKiteOrdersResponse: allOrders }, + initialJobData: jobData + }) + } else { + // all hedges are enabled, + // turn on auto square off on those positions + // as they won't have SL orders + if (hedgeOrders.length) { + await addToAutoSquareOffQueue({ + squareOffType: ASO_TYPE.OPEN_POSITION_SQUARE_OFF, + jobResponse: { rawKiteOrdersResponse: hedgeOrders }, + initialJobData: jobData + }) + } + } + } + return { _nextTradingQueue, rawKiteOrdersResponse: statefulOrders, diff --git a/lib/utils.ts b/lib/utils.ts index 8dfa8b84..3c02cb57 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1398,8 +1398,9 @@ export const convertSllToMarketOrder = async ( order: KiteOrder ): Promise => { // ensure order is not in complete state - const completedOrder = await getOrderHistory(kite, order.order_id!) + const completedOrder = await getCompletedOrderFromOrderHistoryById(kite, order.order_id!) if (completedOrder) { + console.log(`order #${order.order_id} convertSllToMarketOrder already completed`) return } return withRemoteRetry(() => From b2cfc6dee1e9f9e12710f9716f31c901b652c05b Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 13 Dec 2021 14:17:43 +0530 Subject: [PATCH 03/16] increase heap size and new limit --- lib/constants.ts | 2 +- package.json | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index 5ac0d290..c146b69c 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -47,7 +47,7 @@ export const INSTRUMENT_DETAILS: Record = { strikeStepSize: 50, // [11501-17250] // freezeQty: 200 - freezeQty: 1800 + freezeQty: 2800 }, [INSTRUMENTS.BANKNIFTY]: { lotSize: 25, diff --git a/package.json b/package.json index 6c2b5e30..9ef7fe06 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "NODE_OPTIONS='--inspect' next dev", "build": "next build", - "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080}", + "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080} --max-old-space-size=4096", "lint": "next lint --quiet", "test": "jest ./__tests__ --testPathIgnorePatterns support/*", "unit-test": "jest ./__tests__/unit --detectOpenHandles", @@ -13,9 +13,7 @@ "format": "prettier-standard --format" }, "lint-staged": { - "*": [ - "prettier-standard --lint" - ] + "*": ["prettier-standard --lint"] }, "dependencies": { "@date-io/date-fns": "^1.3.13", @@ -90,7 +88,5 @@ "pre-commit": "lint-staged" } }, - "cacheDirectories": [ - ".next/cache" - ] + "cacheDirectories": [".next/cache"] } From b7f579dcac446f081167616cbfa0af9376cebb6b Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 13 Dec 2021 15:23:22 +0530 Subject: [PATCH 04/16] lesser than 512mb --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ef7fe06..0f31dc8f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "NODE_OPTIONS='--inspect' next dev", "build": "next build", - "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080} --max-old-space-size=4096", + "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080} --max-old-space-size=404", "lint": "next lint --quiet", "test": "jest ./__tests__ --testPathIgnorePatterns support/*", "unit-test": "jest ./__tests__/unit --detectOpenHandles", From 8b3cc6b82bc2ac4b5b616abd08b73f7ca40ae898 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 13 Dec 2021 15:26:42 +0530 Subject: [PATCH 05/16] 1gb --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f31dc8f..7229c321 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "NODE_OPTIONS='--inspect' next dev", "build": "next build", - "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080} --max-old-space-size=404", + "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080} --max-old-space-size=1024", "lint": "next lint --quiet", "test": "jest ./__tests__ --testPathIgnorePatterns support/*", "unit-test": "jest ./__tests__/unit --detectOpenHandles", From c64656ad990ddf7e88e779d97cba06fad1e46264 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 13 Dec 2021 15:46:41 +0530 Subject: [PATCH 06/16] updated method --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7229c321..642d789b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "NODE_OPTIONS='--inspect' next dev", "build": "next build", - "start": "node ./bootup.js & TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080} --max-old-space-size=1024", + "start": "node ./bootup.js & NODE_OPTIONS=--max-old-space-size=1024 TZ=Asia/Kolkata next start -H 0.0.0.0 -p ${PORT:-8080}", "lint": "next lint --quiet", "test": "jest ./__tests__ --testPathIgnorePatterns support/*", "unit-test": "jest ./__tests__/unit --detectOpenHandles", From 1af75fe78bf73e1a66ed42ca193e31110062a359 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Sun, 19 Dec 2021 17:05:54 +0530 Subject: [PATCH 07/16] fx: stop continuous logging and fix withRemoteRetry usage --- .../multiLegPremiumThreshold.ts | 21 +++++++------------ lib/queue-processor/exitTradingQueue.ts | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/exit-strategies/multiLegPremiumThreshold.ts b/lib/exit-strategies/multiLegPremiumThreshold.ts index 99ab510a..2d71c4c2 100644 --- a/lib/exit-strategies/multiLegPremiumThreshold.ts +++ b/lib/exit-strategies/multiLegPremiumThreshold.ts @@ -44,19 +44,14 @@ import { import { doSquareOffPositions } from './autoSquareOff' -const patchTradeWithTrailingSL = async ({ dbId, trailingSl }) => { - try { - await patchDbTrade({ - _id: dbId, - patchProps: { - liveTrailingSl: trailingSl, - lastTrailingSlSetAt: dayjs().format() - } - }) - } catch (e) { - console.log('🔴 [patchTradeWithTrailingSL] error', e) - } -} +const patchTradeWithTrailingSL = async ({ dbId, trailingSl }) => + await patchDbTrade({ + _id: dbId, + patchProps: { + liveTrailingSl: trailingSl, + lastTrailingSlSetAt: dayjs().format() + } + }) const tradeHeartbeat = async dbId => { const data = await patchDbTrade({ diff --git a/lib/queue-processor/exitTradingQueue.ts b/lib/queue-processor/exitTradingQueue.ts index 12aa51a5..87b567a0 100644 --- a/lib/queue-processor/exitTradingQueue.ts +++ b/lib/queue-processor/exitTradingQueue.ts @@ -66,7 +66,7 @@ const worker = new Worker( const exitOrders = await processJob(job.data) return exitOrders } catch (e) { - console.log(e.message ? e.message : e) + // console.log(e.message ? e.message : e) throw new Error(e) } }, From 090db806e0334653a7880ab08e097d343a21464d Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 20 Dec 2021 12:03:50 +0530 Subject: [PATCH 08/16] reduced BNF freeze for testing --- lib/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.ts b/lib/constants.ts index c146b69c..9a2dd7e3 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -58,7 +58,7 @@ export const INSTRUMENT_DETAILS: Record = { strikeStepSize: 100, // [27501-40000] // freezeQty: 100 - freezeQty: 1200 + freezeQty: 75 }, [INSTRUMENTS.FINNIFTY]: { lotSize: 40, From a7abd5f9a069bab536b6bc6114ea37803d8a0756 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 20 Dec 2021 20:05:57 +0530 Subject: [PATCH 09/16] ft: flag to selectively disable csl (#108) * ft: flag to selectively disable csl * update msg --- pages/api/trades_day.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pages/api/trades_day.ts b/pages/api/trades_day.ts index cd9f2149..8f80f3fc 100644 --- a/pages/api/trades_day.ts +++ b/pages/api/trades_day.ts @@ -6,6 +6,7 @@ import { customAlphabet } from 'nanoid' import { tradingQueue, addToNextQueue, TRADING_Q_NAME } from '../../lib/queue' import { ERROR_STRINGS, STRATEGIES_DETAILS } from '../../lib/constants' +import { EXIT_STRATEGIES } from '../../lib/constants' import console from '../../lib/logging' import withSession from '../../lib/session' @@ -66,6 +67,19 @@ async function createJob ({ ) } + if (jobData.exitStrategy === EXIT_STRATEGIES.MULTI_LEG_PREMIUM_THRESHOLD) { + if ( + process.env.DISABLE_COMBINED_PREMIUM && + JSON.parse(process.env.DISABLE_COMBINED_PREMIUM) + ) { + return Promise.reject( + new Error( + 'Combined SL is temporarily unavailable due to memory leak issues..' + ) + ) + } + } + return addToNextQueue( { ...jobData, From d9677eafa86514b0740c4b5c4af4f6db2b2ad076 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Tue, 21 Dec 2021 09:57:16 +0530 Subject: [PATCH 10/16] Update multiLegPremiumThreshold.ts --- lib/exit-strategies/multiLegPremiumThreshold.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/exit-strategies/multiLegPremiumThreshold.ts b/lib/exit-strategies/multiLegPremiumThreshold.ts index 2d71c4c2..1b630a5f 100644 --- a/lib/exit-strategies/multiLegPremiumThreshold.ts +++ b/lib/exit-strategies/multiLegPremiumThreshold.ts @@ -39,7 +39,8 @@ import { syncGetKiteInstance, withRemoteRetry, patchDbTrade, - getMultipleInstrumentPrices + getMultipleInstrumentPrices, + logDeep } from '../utils' import { doSquareOffPositions } from './autoSquareOff' @@ -275,13 +276,13 @@ async function multiLegPremiumThreshold ({ legOrder => legOrder.tradingsymbol === losingLeg.tradingSymbol ) ) - // console.log('squareOffLosingLegs', logDeep(squareOffLosingLegs)) + console.log('squareOffLosingLegs', logDeep(squareOffLosingLegs)) const bringToCostOrders = winningLegs.map(winningLeg => legsOrders.find( legOrder => legOrder.tradingsymbol === winningLeg.tradingSymbol ) ) - // console.log('bringToCostOrders', logDeep(bringToCostOrders)) + console.log('bringToCostOrders', logDeep(bringToCostOrders)) // 1. square off losing legs await doSquareOffPositions( squareOffLosingLegs as KiteOrder[], From 140afb66e1bfb6ba46b541f3a0f1c63af8b5871c Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Tue, 4 Jan 2022 00:27:44 +0530 Subject: [PATCH 11/16] jan 2022 update: nf freeze qty --- lib/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.ts b/lib/constants.ts index c146b69c..5ac0d290 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -47,7 +47,7 @@ export const INSTRUMENT_DETAILS: Record = { strikeStepSize: 50, // [11501-17250] // freezeQty: 200 - freezeQty: 2800 + freezeQty: 1800 }, [INSTRUMENTS.BANKNIFTY]: { lotSize: 25, From 728bb901df4129f9f01e3172442d366c449b979c Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Tue, 1 Mar 2022 21:39:54 +0530 Subject: [PATCH 12/16] remove DO disclaimer --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 03a63de4..17ce241c 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ _Update - Redislabs free tier drops connections very often. Recommend upgrading ## 1-click Installation -_Update - DigitalOcean's app platform is terribly slow. Recommend using render.com for all new installations. All other instructions remain as is._ - [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy) or, deploy the application on DigitalOcean's (DO) apps platform. From a7f40f829515e85593847684aab8992089dc8923 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Mon, 21 Mar 2022 22:49:05 +0530 Subject: [PATCH 13/16] fx: updated holiday list for 2022 (#133) * fx: updated holiday list for 2022 * fix string --- lib/utils.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/utils.ts b/lib/utils.ts index f8528946..7183f66e 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -544,7 +544,20 @@ const marketHolidays = [ ['October 15,2021', 'Friday'], ['November 04,2021', 'Thursday'], ['November 05,2021', 'Friday'], - ['November 19,2021', 'Friday'] + ['November 19,2021', 'Friday'], + ['January 26,2022', 'Wednesday'], + ['March 01,2022', 'Tuesday'], + ['March 18,2022', 'Friday'], + ['April 14,2022', 'Thursday'], + ['April 15,2022', 'Friday'], + ['May 03,2022', 'Tuesday'], + ['August 09,2022', 'Tuesday'], + ['August 15,2022', 'Monday'], + ['August 31,2022', 'Wednesday'], + ['October 05,2022', 'Wednesday'], + ['October 24,2022', 'Monday'], + ['October 26,2022', 'Wednesday'], + ['November 08,2022', 'Tuesday'] ] export const isDateHoliday = (date: Dayjs) => { From 559aad841c5c1391f30e5ddafc374f2cd25adfbf Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Fri, 1 Apr 2022 13:35:33 +0530 Subject: [PATCH 14/16] ft: memory leak issue fix attempt #1 --- lib/exit-strategies/multiLegPremiumThreshold.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/exit-strategies/multiLegPremiumThreshold.ts b/lib/exit-strategies/multiLegPremiumThreshold.ts index 1b630a5f..f9f2f69f 100644 --- a/lib/exit-strategies/multiLegPremiumThreshold.ts +++ b/lib/exit-strategies/multiLegPremiumThreshold.ts @@ -140,7 +140,14 @@ async function multiLegPremiumThreshold ({ '🔴 [multiLegPremiumThreshold] getInstrumentPrice error', error ) - return Promise.reject(new Error('Kite APIs acting up')) + // [TODO] see if we can resolve this and add back to the queue to prevent memory leak issues + await addToNextQueue(initialJobData, { + _nextTradingQueue: EXIT_TRADING_Q_NAME, + rawKiteOrdersResponse, + squareOffOrders + }) + + return Promise.resolve('Kite APIs acting up!') } const liveTotalPremium = tradingSymbols.reduce((sum, tradingSymbol) => { @@ -222,7 +229,12 @@ async function multiLegPremiumThreshold ({ if (liveTotalPremium < checkAgainstSl) { const rejectMsg = `🟢 [multiLegPremiumThreshold] liveTotalPremium (${liveTotalPremium}) < threshold (${checkAgainstSl})` - return Promise.reject(new Error(rejectMsg)) + await addToNextQueue(initialJobData, { + _nextTradingQueue: EXIT_TRADING_Q_NAME, + rawKiteOrdersResponse, + squareOffOrders + }) + return Promise.resolve(rejectMsg) } // terminate the checker From 527f7bfdac6b29f5e4522da0ac239f2bdfa316f6 Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Fri, 1 Apr 2022 15:05:27 +0530 Subject: [PATCH 15/16] updated freeze qty --- lib/constants.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index d9093b01..767fa474 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -57,8 +57,7 @@ export const INSTRUMENT_DETAILS: Record = { exchange: 'NSE', strikeStepSize: 100, // [27501-40000] - // freezeQty: 100 - freezeQty: 75 + freezeQty: 1200 }, [INSTRUMENTS.FINNIFTY]: { lotSize: 40, From 06b2a728725fe532e3a9347c62e5bd5ce9401c0f Mon Sep 17 00:00:00 2001 From: Aakash Goel Date: Tue, 5 Apr 2022 18:18:57 +0530 Subject: [PATCH 16/16] fx: prevent queue bloat up --- lib/queue-processor/exitTradingQueue.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/queue-processor/exitTradingQueue.ts b/lib/queue-processor/exitTradingQueue.ts index 87b567a0..f01f300f 100644 --- a/lib/queue-processor/exitTradingQueue.ts +++ b/lib/queue-processor/exitTradingQueue.ts @@ -85,10 +85,11 @@ worker.on('error', err => { console.log('🔴 [exitTradingQueue] worker error', err) }) -// worker.on('completed', (job) => { -// // const { id, name } = job -// // console.log('// job has completed', { id, name }) -// }) +worker.on('completed', async job => { + await job.remove() + // const { id, name } = job + // console.log('// job has completed', { id, name }) +}) // worker.on('failed', (job) => { // try {