@engineering-tf/shared 1.0.0

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.
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractExpirationDateFromOptionSymbol = exports.extractStrikePriceFromOptionSymbol = exports.extractOptionTypeFromOptionSymbol = exports.extractSymbolFromOptionSymbol = exports.calculateRecordOptionSymbolUtil = exports.calculateRecordOptionSymbol = exports.calculateTtl = exports.calRecordId = exports.calculateMinMaxFromTableFiltersItem = exports.calculateRecordSentimentUtil = exports.calculateRecordSentiment = exports.compareTwoNullableValue = exports.calculateDeltaImpact = exports.calculateDeltaExposureUtil = exports.calculateDeltaExposure = exports.calculateRecordMoneynessUtil = exports.calculateRecordMoneyness = exports.calculateRecordSideUtil = exports.calculateRecordSide = exports.calculateRecordExpiryDaysUtil = exports.calculateRecordExpiryDays = exports.passOpeningFilterFull = exports.passOpeningFilter = void 0;
4
+ var shared_1 = require("../../types/shared");
5
+ var date_functions_1 = require("./date-functions");
6
+ var math_functions_1 = require("./math-functions");
7
+ /**
8
+ * opening的定义是size 是今天最大一个订单以保证不是当日内的换仓, 因为他的size比当日所有的剩余的oi+volume都大, 导致无法被换仓, 这样能保证肯定是开仓
9
+ * 如果只是size > oi, 但今天至今交易的volume可能可以跟这个order进行交换, 同时也要大于今日volume
10
+ * @param record
11
+ * @returns
12
+ */
13
+ function passOpeningFilter(record) {
14
+ /**if the volume contains size */
15
+ if (record.volume && record.size > record.volume - record.size + record.open_interest)
16
+ return 1;
17
+ return -1;
18
+ }
19
+ exports.passOpeningFilter = passOpeningFilter;
20
+ function passOpeningFilterFull(record) {
21
+ /**if the volume contains size */
22
+ if (record.daily_volume && record.size > record.daily_volume - record.size + record.oi)
23
+ return true;
24
+ return false;
25
+ }
26
+ exports.passOpeningFilterFull = passOpeningFilterFull;
27
+ /**
28
+ * @deprecated potential bugs when the we don't get the data in time, please use calculateRecordExpiryDaysUtil instead
29
+ * @param date_expiration
30
+ * @returns
31
+ */
32
+ function calculateRecordExpiryDays(date_expiration) {
33
+ return (0, date_functions_1.getDiffDaysBetweenFutureAndToday)(date_expiration);
34
+ }
35
+ exports.calculateRecordExpiryDays = calculateRecordExpiryDays;
36
+ function calculateRecordExpiryDaysUtil(date_expiration, date) {
37
+ return (0, date_functions_1.getDiffDaysBetweenFutureAndPast)(date_expiration, date);
38
+ }
39
+ exports.calculateRecordExpiryDaysUtil = calculateRecordExpiryDaysUtil;
40
+ /**
41
+ * @description
42
+ * Decide the price side by the price
43
+ */
44
+ function calculateRecordSide(record) {
45
+ return calculateRecordSideUtil(record.ask, record.bid, record.price);
46
+ }
47
+ exports.calculateRecordSide = calculateRecordSide;
48
+ function calculateRecordSideUtil(ask, bid, price) {
49
+ var UPPER_CAP = 0.75, LOWER_CAP = 0.25;
50
+ var side;
51
+ if (bid === 0) {
52
+ side = shared_1.SIDE_LABEL.ASK;
53
+ }
54
+ else if (ask === bid) {
55
+ side = shared_1.SIDE_LABEL.MID;
56
+ }
57
+ else {
58
+ var aggressor_ind = (price - bid) / (ask - bid);
59
+ if (aggressor_ind > 1)
60
+ side = shared_1.SIDE_LABEL.ABOVE_ASK;
61
+ else if (aggressor_ind <= 1 && aggressor_ind > UPPER_CAP)
62
+ side = shared_1.SIDE_LABEL.ASK;
63
+ else if (aggressor_ind < 0)
64
+ side = shared_1.SIDE_LABEL.BELOW_BID;
65
+ else if (aggressor_ind >= 0 && aggressor_ind < LOWER_CAP)
66
+ side = shared_1.SIDE_LABEL.BID;
67
+ else
68
+ side = shared_1.SIDE_LABEL.MID;
69
+ }
70
+ return side;
71
+ }
72
+ exports.calculateRecordSideUtil = calculateRecordSideUtil;
73
+ function calculateRecordMoneyness(record) {
74
+ return calculateRecordMoneynessUtil(record.strike_price, record.ref, record.put_call);
75
+ }
76
+ exports.calculateRecordMoneyness = calculateRecordMoneyness;
77
+ function calculateRecordMoneynessUtil(strike_price, ref, put_call) {
78
+ if (ref === strike_price)
79
+ return shared_1.MONEYNESS_LABEL.ATM;
80
+ return put_call === shared_1.CALL_PUT_TAG.CALL
81
+ ? ref >= strike_price
82
+ ? shared_1.MONEYNESS_LABEL.ITM
83
+ : shared_1.MONEYNESS_LABEL.OTM
84
+ : ref <= strike_price
85
+ ? shared_1.MONEYNESS_LABEL.ITM
86
+ : shared_1.MONEYNESS_LABEL.OTM;
87
+ }
88
+ exports.calculateRecordMoneynessUtil = calculateRecordMoneynessUtil;
89
+ /**
90
+ * delta exposure => delta impact in shares
91
+ * calculate the equivalent shares the dealer has to hedge,
92
+ * always positive, because put delta always negative, but it doesn't mean this put trade is a bearish one.
93
+ * TODO: it is going to be replaced by cron function
94
+ * @param record
95
+ * @returns
96
+ */
97
+ function calculateDeltaExposure(record) {
98
+ return calculateDeltaExposureUtil(record.delta, record.size);
99
+ }
100
+ exports.calculateDeltaExposure = calculateDeltaExposure;
101
+ function calculateDeltaExposureUtil(delta, size) {
102
+ if (delta) {
103
+ return Math.abs((0, math_functions_1.fixFloatPrecisionToNumber)(size * 100 * delta, 0));
104
+ }
105
+ return 0; // Return 0 instead of null
106
+ }
107
+ exports.calculateDeltaExposureUtil = calculateDeltaExposureUtil;
108
+ /**
109
+ * calculate the impact on the stock from the delta exposure,
110
+ * always positive
111
+ * @param record
112
+ * @returns
113
+ */
114
+ function calculateDeltaImpact(deltaExposure, avgDailyStockVol) {
115
+ return avgDailyStockVol || avgDailyStockVol === 0 ? (0, math_functions_1.fixFloatPrecisionToNumber)(Math.abs(deltaExposure) / avgDailyStockVol * 100, 5) : 0; // Return 0 instead of null
116
+ }
117
+ exports.calculateDeltaImpact = calculateDeltaImpact;
118
+ function compareTwoNullableValue(a, b) {
119
+ if (!a && !b)
120
+ return -1; // a before b
121
+ if (a && b)
122
+ return a - b;
123
+ if (!a)
124
+ return -1;
125
+ else
126
+ return 1;
127
+ }
128
+ exports.compareTwoNullableValue = compareTwoNullableValue;
129
+ function calculateRecordSentiment(record) {
130
+ return calculateRecordSentimentUtil(record.side, record.put_call);
131
+ }
132
+ exports.calculateRecordSentiment = calculateRecordSentiment;
133
+ function calculateRecordSentimentUtil(side, put_call) {
134
+ if (((side === shared_1.SIDE_LABEL.ASK || side === shared_1.SIDE_LABEL.ABOVE_ASK) && put_call === shared_1.CALL_PUT_TAG.CALL)
135
+ || ((side === shared_1.SIDE_LABEL.BID || side === shared_1.SIDE_LABEL.BELOW_BID) && put_call === shared_1.CALL_PUT_TAG.PUT))
136
+ return shared_1.SENTIMENT_TAG.BULLISH;
137
+ if (((side === shared_1.SIDE_LABEL.ASK || side === shared_1.SIDE_LABEL.ABOVE_ASK) && put_call === shared_1.CALL_PUT_TAG.PUT)
138
+ || ((side === shared_1.SIDE_LABEL.BID || side === shared_1.SIDE_LABEL.BELOW_BID) && put_call === shared_1.CALL_PUT_TAG.CALL))
139
+ return shared_1.SENTIMENT_TAG.BEARISH;
140
+ return shared_1.SENTIMENT_TAG.NEUTRAL;
141
+ }
142
+ exports.calculateRecordSentimentUtil = calculateRecordSentimentUtil;
143
+ /**
144
+ *
145
+ * @param ["32~76"]
146
+ * special case: ["-2.2~-1.1"]
147
+ * @returns [32,76] or [-2.2,-1.1]
148
+ */
149
+ function calculateMinMaxFromTableFiltersItem(value) {
150
+ if (!value) {
151
+ return [null, null];
152
+ }
153
+ var input = value[0];
154
+ if (!input.includes('-') && !input.includes('~')) {
155
+ throw new Error("Invalid value format: ".concat(JSON.stringify(input), " does not contain a valid separator"));
156
+ }
157
+ var separator = input.includes('~') ? '~' : '-'; //check '-' is for backfilled consideration
158
+ var _a = input.split(separator), min = _a[0], max = _a[1];
159
+ return [
160
+ min === 'null' ? null : parseFloat(min),
161
+ max === 'null' ? null : parseFloat(max)
162
+ ];
163
+ }
164
+ exports.calculateMinMaxFromTableFiltersItem = calculateMinMaxFromTableFiltersItem;
165
+ /**
166
+ * @description used to calculate custom id, we need to custom id to combine smart flow with full flow into ddb.
167
+ * @usage CronService ProcessingService
168
+ * @param record
169
+ * @returns STT-20250117-65-PUT-20230501-10:14-250-6.80
170
+ */
171
+ function calRecordId(record) {
172
+ var date = record.date, ticker = record.ticker, date_expiration = record.date_expiration, put_call = record.put_call, strike_price = record.strike_price, size = record.size, time = record.time, price = record.price;
173
+ var new_date_expiration = (0, date_functions_1.convertDateFormatToYYYYMMDD)(date_expiration);
174
+ var new_date = (0, date_functions_1.convertDateFormatToYYYYMMDD)(date);
175
+ var newTime = "".concat(time.split(":")[0], ":").concat(time.split(":")[1]); // remove seconds
176
+ var newStrike = processStrikePrice(record.strike_price); //24.00 or 24.50
177
+ var newPrice = (0, math_functions_1.fixFloatPrecisionToString)(record.price, 2); // 6.80 or 3.00
178
+ return "".concat(ticker, "-").concat(new_date_expiration, "-").concat(newStrike, "-").concat(put_call, "-").concat(new_date, "-").concat(newTime, "-").concat(size, "-").concat(newPrice);
179
+ }
180
+ exports.calRecordId = calRecordId;
181
+ /**
182
+ * @usage cron-service process-service
183
+ * @default 365 days
184
+ * @returns
185
+ */
186
+ function calculateTtl(days) {
187
+ if (days === void 0) { days = 365; }
188
+ return Math.round(Date.now() / 1000) + 86400 * days; //ttl is set to oen year later
189
+ }
190
+ exports.calculateTtl = calculateTtl;
191
+ /**
192
+ * calculate the record option symbol
193
+ * @usage api-service cron-service process-service
194
+ * @param record
195
+ * @ex: CVS230818C00077500 => CVS Oct 23 2020 $77.50 Call
196
+ * PANW250117C00173330 => PANW Jan 17 2025 $173.33 Call
197
+ */
198
+ function calculateRecordOptionSymbol(record) {
199
+ return calculateRecordOptionSymbolUtil(record.ticker, record.date_expiration, record.put_call, record.strike_price);
200
+ }
201
+ exports.calculateRecordOptionSymbol = calculateRecordOptionSymbol;
202
+ function calculateRecordOptionSymbolUtil(ticker, date_expiration, put_call, strike_price) {
203
+ var expiryDate = (0, date_functions_1.convertDateFormatToYYYYMMDD)(date_expiration).substring(2);
204
+ var strNum = processStrikePrice(strike_price); // 将数字转为字符串,并保留两位小数
205
+ /* 77.55 => 00077550, credits to chatgpt */
206
+ var parts = strNum.split('.'); // 拆分整数部分和小数部分
207
+ var intPart = parts[0];
208
+ var decimalPart = parts[1] || '0'; // 如果没有小数部分,默认为0
209
+ var paddedIntPart = intPart.padStart(5, '0'); // 将整数部分用0填充到5位
210
+ var paddedDecimalPart = decimalPart.padEnd(3, '0'); // 将小数部分用0填充到2位
211
+ var strike_price_string = paddedIntPart + paddedDecimalPart;
212
+ return "".concat(ticker).concat(expiryDate).concat(put_call === shared_1.CALL_PUT_TAG.CALL ? "C" : "P").concat(strike_price_string);
213
+ }
214
+ exports.calculateRecordOptionSymbolUtil = calculateRecordOptionSymbolUtil;
215
+ function processStrikePrice(strike_price) {
216
+ return Number(strike_price).toFixed(2);
217
+ }
218
+ /**
219
+ """
220
+ Extracts the underlying stock symbol from a standard option symbol.
221
+
222
+ Args:
223
+ optionSymbol: The option symbol string, e.g., "AAPL240412C00175000".
224
+
225
+ Returns:
226
+ The underlying stock symbol, e.g., "AAPL".
227
+ @usage api-service websocket-service
228
+
229
+ */
230
+ function extractSymbolFromOptionSymbol(optionSymbol) {
231
+ // Standard option symbols have the symbol before the expiration date.
232
+ // Find the first occurrence of a digit, which usually marks the start of the date.
233
+ var index = optionSymbol.search(/\d/);
234
+ // If a digit is found, return the substring before it.
235
+ if (index !== -1) {
236
+ return optionSymbol.substring(0, index);
237
+ }
238
+ else {
239
+ throw new Error("Error in extracting symbol from optionSymbol: ".concat(optionSymbol));
240
+ }
241
+ }
242
+ exports.extractSymbolFromOptionSymbol = extractSymbolFromOptionSymbol;
243
+ /**
244
+ * """
245
+ Extracts the option type (CALL or PUT) from the option symbol string.
246
+
247
+ Args:
248
+ optionSymbol: The option symbol string, e.g., "AAPL240412C00175000", "QTTB1241018C00005000"
249
+
250
+ Returns:
251
+ "CALL", "PUT", or null if not found.
252
+ """
253
+ */
254
+ function extractOptionTypeFromOptionSymbol(optionSymbol) {
255
+ // Find the index of 'C' or 'P' after the date portion
256
+ var optionTypeIndex = optionSymbol.search(/\d{6}[CP]/);
257
+ if (optionTypeIndex !== -1) {
258
+ var optionType = optionSymbol.charAt(optionTypeIndex + 6); // +6 to get the character after the date
259
+ if (optionType === "C") {
260
+ return shared_1.CALL_PUT_TAG.CALL;
261
+ }
262
+ else if (optionType === "P") {
263
+ return shared_1.CALL_PUT_TAG.PUT;
264
+ }
265
+ }
266
+ throw new Error("Failed to extract option type from: ".concat(optionSymbol));
267
+ }
268
+ exports.extractOptionTypeFromOptionSymbol = extractOptionTypeFromOptionSymbol;
269
+ /**
270
+ * """
271
+ Extracts the strike price from a standard option symbol.
272
+
273
+ Args:
274
+ optionSymbol: The option symbol string, e.g., "AAPL240412C00175000".
275
+
276
+ Returns:
277
+ The strike price as a number (e.g., 175), or null if not found or invalid.
278
+ """ GLYC241115C00000500 => 0.5
279
+ SPY241030C00582000 => 582
280
+ ZK241220P00022500 => 22.5
281
+ * @param optionSymbol
282
+ * @returns
283
+ */
284
+ function extractStrikePriceFromOptionSymbol(optionSymbol) {
285
+ var strikePriceCents = parseInt(optionSymbol.slice(-3), 0) / 1000;
286
+ var strikePriceDollars = parseInt(optionSymbol.slice(-8, -3), 0);
287
+ if (!isNaN(strikePriceDollars) && !isNaN(strikePriceCents)) {
288
+ return strikePriceDollars + strikePriceCents;
289
+ }
290
+ return null;
291
+ }
292
+ exports.extractStrikePriceFromOptionSymbol = extractStrikePriceFromOptionSymbol;
293
+ function extractExpirationDateFromOptionSymbol(optionSymbol) {
294
+ // The expiration date is at positions 5 to 12 in the format "YYMMDD"
295
+ // So, we start extraction from index 4 (0-based index) and end at index 11
296
+ var rawDate = optionSymbol.slice(-15);
297
+ // The extracted date is in "YYMMDD" format
298
+ // We need to convert it into "YYYY-MM-DD"
299
+ // First, add "20" at the beginning to convert "YY" into "YYYY"
300
+ var year = "20" + rawDate.substring(0, 2);
301
+ // Next, extract the month and day
302
+ var month = rawDate.substring(2, 4);
303
+ var day = rawDate.substring(4, 6);
304
+ // Combine them together into the desired format
305
+ var formattedDate = "".concat(year, "-").concat(month, "-").concat(day);
306
+ return formattedDate;
307
+ }
308
+ exports.extractExpirationDateFromOptionSymbol = extractExpirationDateFromOptionSymbol;
@@ -0,0 +1,4 @@
1
+ export declare const encryptPassword: (password: string) => Promise<any>;
2
+ export declare const decryptPassword: (password: string) => Promise<any>;
3
+ export declare const localLogging: (msg: string) => void;
4
+ export declare function waitForRandomSecs(maxSec?: number): Promise<void>;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.waitForRandomSecs = exports.localLogging = exports.decryptPassword = exports.encryptPassword = void 0;
40
+ var CryptoJS = require("crypto-js");
41
+ var SECRET = "tradingflow_isidjfiw";
42
+ var encryptPassword = function (password) { return __awaiter(void 0, void 0, void 0, function () {
43
+ var ciphertext;
44
+ return __generator(this, function (_a) {
45
+ ciphertext = CryptoJS.AES.encrypt(password, SECRET).toString();
46
+ return [2 /*return*/, ciphertext];
47
+ });
48
+ }); };
49
+ exports.encryptPassword = encryptPassword;
50
+ var decryptPassword = function (password) { return __awaiter(void 0, void 0, void 0, function () {
51
+ var bytes, originalText;
52
+ return __generator(this, function (_a) {
53
+ bytes = CryptoJS.AES.decrypt(password, SECRET);
54
+ originalText = bytes.toString(CryptoJS.enc.Utf8);
55
+ return [2 /*return*/, originalText];
56
+ });
57
+ }); };
58
+ exports.decryptPassword = decryptPassword;
59
+ var localLogging = function (msg) {
60
+ if (process.env.NODE_ENV !== 'production' && process.env.CUSTOM_NODE_ENV !== 'production') {
61
+ console.log("[LOCAL ONLY LOG] ".concat(msg));
62
+ }
63
+ };
64
+ exports.localLogging = localLogging;
65
+ function waitForRandomSecs(maxSec) {
66
+ if (maxSec === void 0) { maxSec = 10; }
67
+ return __awaiter(this, void 0, void 0, function () {
68
+ return __generator(this, function (_a) {
69
+ switch (_a.label) {
70
+ case 0: return [4 /*yield*/, randomSleep(maxSec)];
71
+ case 1:
72
+ _a.sent();
73
+ return [2 /*return*/];
74
+ }
75
+ });
76
+ });
77
+ }
78
+ exports.waitForRandomSecs = waitForRandomSecs;
79
+ function randomSleep(maxSec) {
80
+ return __awaiter(this, void 0, void 0, function () {
81
+ var sleepTime;
82
+ return __generator(this, function (_a) {
83
+ switch (_a.label) {
84
+ case 0:
85
+ sleepTime = Math.floor(Math.random() * maxSec) + 1;
86
+ console.log("Sleeping for ".concat(sleepTime, " seconds..."));
87
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, sleepTime * 1000); })];
88
+ case 1:
89
+ _a.sent();
90
+ return [2 /*return*/];
91
+ }
92
+ });
93
+ });
94
+ }
@@ -0,0 +1,14 @@
1
+ import { OptionFlowItem } from '../../types/shared';
2
+ import { OptionFlowItemFull, OptionFlowItemFullWebApp } from '../../types/optionTrades';
3
+ /**
4
+ * weight components
5
+ * 1. deltaExposure and deltaImpact
6
+ * 2. whether is a opening open interest
7
+ * 3. Combination:
8
+ * SELL CALL + BEARISH + OPENING + High IV + => Institute SELL CALL
9
+ * BUY PUT + BEARISH + OPENING + Low IV => Institute BUY PUT
10
+ * TODO: add score, remove existing strategy3
11
+ * FAR OTM + WITH 30DAYS
12
+ */
13
+ export declare function calculateScoreAndStrategy(record: OptionFlowItem): void;
14
+ export declare function calculateScoreAndStrategyOptionTradeFull(record: OptionFlowItemFull): OptionFlowItemFullWebApp;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.calculateScoreAndStrategyOptionTradeFull = exports.calculateScoreAndStrategy = void 0;
15
+ var sigmoid = require('sigmoid');
16
+ var shared_1 = require("../../types/shared");
17
+ var math_functions_1 = require("../common/math-functions");
18
+ var record_function_1 = require("../common/record-function");
19
+ /**
20
+ * weight components
21
+ * 1. deltaExposure and deltaImpact
22
+ * 2. whether is a opening open interest
23
+ * 3. Combination:
24
+ * SELL CALL + BEARISH + OPENING + High IV + => Institute SELL CALL
25
+ * BUY PUT + BEARISH + OPENING + Low IV => Institute BUY PUT
26
+ * TODO: add score, remove existing strategy3
27
+ * FAR OTM + WITH 30DAYS
28
+ */
29
+ function calculateScoreAndStrategy(record) {
30
+ var _a, _b;
31
+ var HIGH_IV = 0.8;
32
+ var LOW_IV = 0.3;
33
+ /**
34
+ * The initial value is the impact value which represent the percentage
35
+ * 2.3 means 2.3% of the ratio for delta exposure and average stock volume.
36
+ * deltaImpact 0 => 0.5 * 100
37
+ * deltaImpact 50 => 0.9 * 100
38
+ * deltaImpact 100 => 1.0 * 100
39
+ */
40
+ var score = calculateSigmoid(record.deltaImpact) * 100;
41
+ /**
42
+ * if it is opening, reward multiplier is 1.3
43
+ */
44
+ var isOpening = (0, record_function_1.passOpeningFilter)(record) >= 0;
45
+ if (!isOpening) {
46
+ score *= 0.8;
47
+ }
48
+ /**
49
+ * check whether the order is potential institutional sell or institutional buy.
50
+ */
51
+ if (record.put_call === shared_1.CALL_PUT_TAG.CALL &&
52
+ (record.side === shared_1.SIDE_LABEL.BID || record.side === shared_1.SIDE_LABEL.BELOW_BID) &&
53
+ record.sentiment === shared_1.SENTIMENT_TAG.BEARISH &&
54
+ isOpening &&
55
+ record.option_activity_type === shared_1.OPTION_ACTIVITY_TYPE.BLOCK &&
56
+ record.iv >= HIGH_IV) {
57
+ (_a = record.strategy_label) === null || _a === void 0 ? void 0 : _a.push(shared_1.STRATEGY_LABEL.INSTITUTE_SELL_CALL);
58
+ }
59
+ else if (record.put_call === shared_1.CALL_PUT_TAG.PUT &&
60
+ (record.side === shared_1.SIDE_LABEL.ASK || record.side === shared_1.SIDE_LABEL.ABOVE_ASK) &&
61
+ record.sentiment === shared_1.SENTIMENT_TAG.BEARISH &&
62
+ isOpening &&
63
+ record.option_activity_type === shared_1.OPTION_ACTIVITY_TYPE.BLOCK &&
64
+ record.iv <= LOW_IV) {
65
+ (_b = record.strategy_label) === null || _b === void 0 ? void 0 : _b.push(shared_1.STRATEGY_LABEL.INSTITUTE_BUY_PUT);
66
+ }
67
+ if (record.side === shared_1.SIDE_LABEL.MID || record.sentiment === shared_1.SENTIMENT_TAG.NEUTRAL) {
68
+ score *= 0.5;
69
+ }
70
+ if (record.underlying_type === shared_1.UNDERLYING_TYPE_TAG.ETF) {
71
+ score *= 0.8;
72
+ }
73
+ score = (0, math_functions_1.fixFloatPrecisionToNumber)(score, 0);
74
+ record.score = score;
75
+ }
76
+ exports.calculateScoreAndStrategy = calculateScoreAndStrategy;
77
+ function calculateScoreAndStrategyOptionTradeFull(record) {
78
+ var HIGH_IV = 0.8;
79
+ var LOW_IV = 0.3;
80
+ /**
81
+ * The initial value is the impact value which represent the percentage
82
+ * 2.3 means 2.3% of the ratio for delta exposure and average stock volume.
83
+ * deltaImpact 0 => 0.5 * 100
84
+ * deltaImpact 50 => 0.9 * 100
85
+ * deltaImpact 100 => 1.0 * 100
86
+ */
87
+ var score = calculateSigmoid(record.dei) * 100;
88
+ var strategy_label = [];
89
+ /**
90
+ * if it is opening, reward multiplier is 1.3
91
+ */
92
+ var isOpening = (0, record_function_1.passOpeningFilterFull)(record);
93
+ if (!isOpening) {
94
+ score *= 0.8;
95
+ }
96
+ /**
97
+ * check whether the order is potential institutional sell or institutional buy.
98
+ */
99
+ if (record.put_call === shared_1.CALL_PUT_TAG.CALL &&
100
+ (record.side === shared_1.SIDE_LABEL.BID || record.side === shared_1.SIDE_LABEL.BELOW_BID) &&
101
+ record.sentiment === shared_1.SENTIMENT_TAG.BEARISH &&
102
+ isOpening &&
103
+ record.option_activity_type === shared_1.OPTION_ACTIVITY_TYPE.BLOCK &&
104
+ record.iv >= HIGH_IV) {
105
+ strategy_label === null || strategy_label === void 0 ? void 0 : strategy_label.push(shared_1.STRATEGY_LABEL.INSTITUTE_SELL_CALL);
106
+ }
107
+ else if (record.put_call === shared_1.CALL_PUT_TAG.PUT &&
108
+ (record.side === shared_1.SIDE_LABEL.ASK || record.side === shared_1.SIDE_LABEL.ABOVE_ASK) &&
109
+ record.sentiment === shared_1.SENTIMENT_TAG.BEARISH &&
110
+ isOpening &&
111
+ record.option_activity_type === shared_1.OPTION_ACTIVITY_TYPE.BLOCK &&
112
+ record.iv <= LOW_IV) {
113
+ strategy_label === null || strategy_label === void 0 ? void 0 : strategy_label.push(shared_1.STRATEGY_LABEL.INSTITUTE_BUY_PUT);
114
+ }
115
+ if (record.side === shared_1.SIDE_LABEL.MID || record.sentiment === shared_1.SENTIMENT_TAG.NEUTRAL) {
116
+ score *= 0.5;
117
+ }
118
+ if (record.underlying_type === shared_1.UNDERLYING_TYPE_TAG.ETF) {
119
+ score *= 0.8;
120
+ }
121
+ score = (0, math_functions_1.fixFloatPrecisionToNumber)(score, 0);
122
+ var result = __assign(__assign({}, record), { score: score, strategy_label: strategy_label, itemOptionChainInfo: null });
123
+ return result;
124
+ }
125
+ exports.calculateScoreAndStrategyOptionTradeFull = calculateScoreAndStrategyOptionTradeFull;
126
+ function calculateSigmoid(value) {
127
+ return sigmoid(value);
128
+ // return makeSigmoid({
129
+ // center: 0,
130
+ // deviation: 10,
131
+ // deviation_output: 0.9,
132
+ // })(value);
133
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@engineering-tf/shared",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "watch": "tsc -w"
15
+ },
16
+ "dependencies": {
17
+ "crypto-js": "^4.2.0",
18
+ "discord-webhook-node": "^1.1.8",
19
+ "moment": "^2.30.1",
20
+ "moment-timezone": "^0.5.31",
21
+ "sigmoid": "^0.0.1",
22
+ "uuid": "^11.0.2"
23
+ },
24
+ "devDependencies": {
25
+ "@types/crypto-js": "^4.2.2",
26
+ "@types/node": "^25.0.3",
27
+ "typescript": "^4.9.5"
28
+ }
29
+ }