@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.
- package/dist/constants/index.d.ts +9 -0
- package/dist/constants/index.js +96 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +25 -0
- package/dist/types/optionChain.d.ts +21 -0
- package/dist/types/optionChain.js +2 -0
- package/dist/types/optionTrades.d.ts +101 -0
- package/dist/types/optionTrades.js +53 -0
- package/dist/types/shared.d.ts +376 -0
- package/dist/types/shared.js +218 -0
- package/dist/types/websocketCF.d.ts +30 -0
- package/dist/types/websocketCF.js +2 -0
- package/dist/utils/common/date-functions.d.ts +45 -0
- package/dist/utils/common/date-functions.js +150 -0
- package/dist/utils/common/discord-functions.d.ts +3 -0
- package/dist/utils/common/discord-functions.js +89 -0
- package/dist/utils/common/math-functions.d.ts +32 -0
- package/dist/utils/common/math-functions.js +118 -0
- package/dist/utils/common/record-function.d.ts +116 -0
- package/dist/utils/common/record-function.js +308 -0
- package/dist/utils/common/util-functions.d.ts +4 -0
- package/dist/utils/common/util-functions.js +94 -0
- package/dist/utils/strategy/calculateScoreAndStrategy.d.ts +14 -0
- package/dist/utils/strategy/calculateScoreAndStrategy.js +133 -0
- package/package.json +29 -0
|
@@ -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
|
+
}
|