Expand synthetic data across S&P 500
Add S&P 500 symbol list and expand synthetic options/equities feeds with varied contracts, sizes, and bursts to keep alerts firing.
This commit is contained in:
parent
41bdd2c73a
commit
7996d00677
4 changed files with 643 additions and 26 deletions
|
|
@ -1 +1,2 @@
|
|||
export * from "./events";
|
||||
export * from "./sp500";
|
||||
|
|
|
|||
507
packages/types/src/sp500.ts
Normal file
507
packages/types/src/sp500.ts
Normal file
|
|
@ -0,0 +1,507 @@
|
|||
export const SP500_SYMBOLS = [
|
||||
"MMM",
|
||||
"AOS",
|
||||
"ABT",
|
||||
"ABBV",
|
||||
"ACN",
|
||||
"ADBE",
|
||||
"AMD",
|
||||
"AES",
|
||||
"AFL",
|
||||
"A",
|
||||
"APD",
|
||||
"ABNB",
|
||||
"AKAM",
|
||||
"ALB",
|
||||
"ARE",
|
||||
"ALGN",
|
||||
"ALLE",
|
||||
"LNT",
|
||||
"ALL",
|
||||
"GOOGL",
|
||||
"GOOG",
|
||||
"MO",
|
||||
"AMZN",
|
||||
"AMCR",
|
||||
"AEE",
|
||||
"AEP",
|
||||
"AXP",
|
||||
"AIG",
|
||||
"AMT",
|
||||
"AWK",
|
||||
"AMP",
|
||||
"AME",
|
||||
"AMGN",
|
||||
"APH",
|
||||
"ADI",
|
||||
"AON",
|
||||
"APA",
|
||||
"APO",
|
||||
"AAPL",
|
||||
"AMAT",
|
||||
"APTV",
|
||||
"ACGL",
|
||||
"ADM",
|
||||
"ANET",
|
||||
"AJG",
|
||||
"AIZ",
|
||||
"T",
|
||||
"ATO",
|
||||
"ADSK",
|
||||
"ADP",
|
||||
"AZO",
|
||||
"AVB",
|
||||
"AVY",
|
||||
"AXON",
|
||||
"BKR",
|
||||
"BALL",
|
||||
"BAC",
|
||||
"BAX",
|
||||
"BDX",
|
||||
"BRK.B",
|
||||
"BBY",
|
||||
"TECH",
|
||||
"BIIB",
|
||||
"BLK",
|
||||
"BX",
|
||||
"XYZ",
|
||||
"BK",
|
||||
"BA",
|
||||
"BKNG",
|
||||
"BSX",
|
||||
"BMY",
|
||||
"AVGO",
|
||||
"BR",
|
||||
"BRO",
|
||||
"BF.B",
|
||||
"BLDR",
|
||||
"BG",
|
||||
"BXP",
|
||||
"CHRW",
|
||||
"CDNS",
|
||||
"CZR",
|
||||
"CPT",
|
||||
"CPB",
|
||||
"COF",
|
||||
"CAH",
|
||||
"KMX",
|
||||
"CCL",
|
||||
"CARR",
|
||||
"CAT",
|
||||
"CBOE",
|
||||
"CBRE",
|
||||
"CDW",
|
||||
"COR",
|
||||
"CNC",
|
||||
"CNP",
|
||||
"CF",
|
||||
"CRL",
|
||||
"SCHW",
|
||||
"CHTR",
|
||||
"CVX",
|
||||
"CMG",
|
||||
"CB",
|
||||
"CHD",
|
||||
"CI",
|
||||
"CINF",
|
||||
"CTAS",
|
||||
"CSCO",
|
||||
"C",
|
||||
"CFG",
|
||||
"CLX",
|
||||
"CME",
|
||||
"CMS",
|
||||
"KO",
|
||||
"CTSH",
|
||||
"COIN",
|
||||
"CL",
|
||||
"CMCSA",
|
||||
"CAG",
|
||||
"COP",
|
||||
"ED",
|
||||
"STZ",
|
||||
"CEG",
|
||||
"COO",
|
||||
"CPRT",
|
||||
"GLW",
|
||||
"CPAY",
|
||||
"CTVA",
|
||||
"CSGP",
|
||||
"COST",
|
||||
"CTRA",
|
||||
"CRWD",
|
||||
"CCI",
|
||||
"CSX",
|
||||
"CMI",
|
||||
"CVS",
|
||||
"DHR",
|
||||
"DRI",
|
||||
"DDOG",
|
||||
"DVA",
|
||||
"DAY",
|
||||
"DECK",
|
||||
"DE",
|
||||
"DELL",
|
||||
"DAL",
|
||||
"DVN",
|
||||
"DXCM",
|
||||
"FANG",
|
||||
"DLR",
|
||||
"DG",
|
||||
"DLTR",
|
||||
"D",
|
||||
"DPZ",
|
||||
"DASH",
|
||||
"DOV",
|
||||
"DOW",
|
||||
"DHI",
|
||||
"DTE",
|
||||
"DUK",
|
||||
"DD",
|
||||
"EMN",
|
||||
"ETN",
|
||||
"EBAY",
|
||||
"ECL",
|
||||
"EIX",
|
||||
"EW",
|
||||
"EA",
|
||||
"ELV",
|
||||
"EMR",
|
||||
"ENPH",
|
||||
"ETR",
|
||||
"EOG",
|
||||
"EPAM",
|
||||
"EQT",
|
||||
"EFX",
|
||||
"EQIX",
|
||||
"EQR",
|
||||
"ERIE",
|
||||
"ESS",
|
||||
"EL",
|
||||
"EG",
|
||||
"EVRG",
|
||||
"ES",
|
||||
"EXC",
|
||||
"EXE",
|
||||
"EXPE",
|
||||
"EXPD",
|
||||
"EXR",
|
||||
"XOM",
|
||||
"FFIV",
|
||||
"FDS",
|
||||
"FICO",
|
||||
"FAST",
|
||||
"FRT",
|
||||
"FDX",
|
||||
"FIS",
|
||||
"FITB",
|
||||
"FSLR",
|
||||
"FE",
|
||||
"FI",
|
||||
"F",
|
||||
"FTNT",
|
||||
"FTV",
|
||||
"FOXA",
|
||||
"FOX",
|
||||
"BEN",
|
||||
"FCX",
|
||||
"GRMN",
|
||||
"IT",
|
||||
"GE",
|
||||
"GEHC",
|
||||
"GEV",
|
||||
"GEN",
|
||||
"GNRC",
|
||||
"GD",
|
||||
"GIS",
|
||||
"GM",
|
||||
"GPC",
|
||||
"GILD",
|
||||
"GPN",
|
||||
"GL",
|
||||
"GDDY",
|
||||
"GS",
|
||||
"HAL",
|
||||
"HIG",
|
||||
"HAS",
|
||||
"HCA",
|
||||
"DOC",
|
||||
"HSIC",
|
||||
"HSY",
|
||||
"HPE",
|
||||
"HLT",
|
||||
"HOLX",
|
||||
"HD",
|
||||
"HON",
|
||||
"HRL",
|
||||
"HST",
|
||||
"HWM",
|
||||
"HPQ",
|
||||
"HUBB",
|
||||
"HUM",
|
||||
"HBAN",
|
||||
"HII",
|
||||
"IBM",
|
||||
"IEX",
|
||||
"IDXX",
|
||||
"ITW",
|
||||
"INCY",
|
||||
"IR",
|
||||
"PODD",
|
||||
"INTC",
|
||||
"ICE",
|
||||
"IFF",
|
||||
"IP",
|
||||
"IPG",
|
||||
"INTU",
|
||||
"ISRG",
|
||||
"IVZ",
|
||||
"INVH",
|
||||
"IQV",
|
||||
"IRM",
|
||||
"JBHT",
|
||||
"JBL",
|
||||
"JKHY",
|
||||
"J",
|
||||
"JNJ",
|
||||
"JCI",
|
||||
"JPM",
|
||||
"K",
|
||||
"KVUE",
|
||||
"KDP",
|
||||
"KEY",
|
||||
"KEYS",
|
||||
"KMB",
|
||||
"KIM",
|
||||
"KMI",
|
||||
"KKR",
|
||||
"KLAC",
|
||||
"KHC",
|
||||
"KR",
|
||||
"LHX",
|
||||
"LH",
|
||||
"LRCX",
|
||||
"LW",
|
||||
"LVS",
|
||||
"LDOS",
|
||||
"LEN",
|
||||
"LII",
|
||||
"LLY",
|
||||
"LIN",
|
||||
"LYV",
|
||||
"LKQ",
|
||||
"LMT",
|
||||
"L",
|
||||
"LOW",
|
||||
"LULU",
|
||||
"LYB",
|
||||
"MTB",
|
||||
"MPC",
|
||||
"MKTX",
|
||||
"MAR",
|
||||
"MMC",
|
||||
"MLM",
|
||||
"MAS",
|
||||
"MA",
|
||||
"MTCH",
|
||||
"MKC",
|
||||
"MCD",
|
||||
"MCK",
|
||||
"MDT",
|
||||
"MRK",
|
||||
"META",
|
||||
"MET",
|
||||
"MTD",
|
||||
"MGM",
|
||||
"MCHP",
|
||||
"MU",
|
||||
"MSFT",
|
||||
"MAA",
|
||||
"MRNA",
|
||||
"MHK",
|
||||
"MOH",
|
||||
"TAP",
|
||||
"MDLZ",
|
||||
"MPWR",
|
||||
"MNST",
|
||||
"MCO",
|
||||
"MS",
|
||||
"MOS",
|
||||
"MSI",
|
||||
"MSCI",
|
||||
"NDAQ",
|
||||
"NTAP",
|
||||
"NFLX",
|
||||
"NEM",
|
||||
"NWSA",
|
||||
"NWS",
|
||||
"NEE",
|
||||
"NKE",
|
||||
"NI",
|
||||
"NDSN",
|
||||
"NSC",
|
||||
"NTRS",
|
||||
"NOC",
|
||||
"NCLH",
|
||||
"NRG",
|
||||
"NUE",
|
||||
"NVDA",
|
||||
"NVR",
|
||||
"NXPI",
|
||||
"ORLY",
|
||||
"OXY",
|
||||
"ODFL",
|
||||
"OMC",
|
||||
"ON",
|
||||
"OKE",
|
||||
"ORCL",
|
||||
"OTIS",
|
||||
"PCAR",
|
||||
"PKG",
|
||||
"PLTR",
|
||||
"PANW",
|
||||
"PSKY",
|
||||
"PH",
|
||||
"PAYX",
|
||||
"PAYC",
|
||||
"PYPL",
|
||||
"PNR",
|
||||
"PEP",
|
||||
"PFE",
|
||||
"PCG",
|
||||
"PM",
|
||||
"PSX",
|
||||
"PNW",
|
||||
"PNC",
|
||||
"POOL",
|
||||
"PPG",
|
||||
"PPL",
|
||||
"PFG",
|
||||
"PG",
|
||||
"PGR",
|
||||
"PLD",
|
||||
"PRU",
|
||||
"PEG",
|
||||
"PTC",
|
||||
"PSA",
|
||||
"PHM",
|
||||
"PWR",
|
||||
"QCOM",
|
||||
"DGX",
|
||||
"RL",
|
||||
"RJF",
|
||||
"RTX",
|
||||
"O",
|
||||
"REG",
|
||||
"REGN",
|
||||
"RF",
|
||||
"RSG",
|
||||
"RMD",
|
||||
"RVTY",
|
||||
"ROK",
|
||||
"ROL",
|
||||
"ROP",
|
||||
"ROST",
|
||||
"RCL",
|
||||
"SPGI",
|
||||
"CRM",
|
||||
"SBAC",
|
||||
"SLB",
|
||||
"STX",
|
||||
"SRE",
|
||||
"NOW",
|
||||
"SHW",
|
||||
"SPG",
|
||||
"SWKS",
|
||||
"SJM",
|
||||
"SW",
|
||||
"SNA",
|
||||
"SOLV",
|
||||
"SO",
|
||||
"LUV",
|
||||
"SWK",
|
||||
"SBUX",
|
||||
"STT",
|
||||
"STLD",
|
||||
"STE",
|
||||
"SYK",
|
||||
"SMCI",
|
||||
"SYF",
|
||||
"SNPS",
|
||||
"SYY",
|
||||
"TMUS",
|
||||
"TROW",
|
||||
"TTWO",
|
||||
"TPR",
|
||||
"TRGP",
|
||||
"TGT",
|
||||
"TEL",
|
||||
"TDY",
|
||||
"TER",
|
||||
"TSLA",
|
||||
"TXN",
|
||||
"TPL",
|
||||
"TXT",
|
||||
"TMO",
|
||||
"TJX",
|
||||
"TKO",
|
||||
"TTD",
|
||||
"TSCO",
|
||||
"TT",
|
||||
"TDG",
|
||||
"TRV",
|
||||
"TRMB",
|
||||
"TFC",
|
||||
"TYL",
|
||||
"TSN",
|
||||
"USB",
|
||||
"UBER",
|
||||
"UDR",
|
||||
"ULTA",
|
||||
"UNP",
|
||||
"UAL",
|
||||
"UPS",
|
||||
"URI",
|
||||
"UNH",
|
||||
"UHS",
|
||||
"VLO",
|
||||
"VTR",
|
||||
"VLTO",
|
||||
"VRSN",
|
||||
"VRSK",
|
||||
"VZ",
|
||||
"VRTX",
|
||||
"VTRS",
|
||||
"VICI",
|
||||
"V",
|
||||
"VST",
|
||||
"VMC",
|
||||
"WRB",
|
||||
"GWW",
|
||||
"WAB",
|
||||
"WBA",
|
||||
"WMT",
|
||||
"DIS",
|
||||
"WBD",
|
||||
"WM",
|
||||
"WAT",
|
||||
"WEC",
|
||||
"WFC",
|
||||
"WELL",
|
||||
"WST",
|
||||
"WDC",
|
||||
"WY",
|
||||
"WSM",
|
||||
"WMB",
|
||||
"WTW",
|
||||
"WDAY",
|
||||
"WYNN",
|
||||
"XEL",
|
||||
"XYL",
|
||||
"YUM",
|
||||
"ZBRA",
|
||||
"ZBH",
|
||||
"ZTS",
|
||||
] as const;
|
||||
|
||||
export type Sp500Symbol = typeof SP500_SYMBOLS[number];
|
||||
|
|
@ -1,22 +1,40 @@
|
|||
import type { EquityPrint } from "@islandflow/types";
|
||||
import { SP500_SYMBOLS, type EquityPrint } from "@islandflow/types";
|
||||
import type { EquityIngestAdapter, EquityIngestHandlers } from "./types";
|
||||
|
||||
type SyntheticEquitiesAdapterConfig = {
|
||||
emitIntervalMs: number;
|
||||
};
|
||||
|
||||
const buildSyntheticPrint = (seq: number, now: number): EquityPrint => {
|
||||
const EXCHANGES = ["NYSE", "NASDAQ", "ARCA", "BATS", "IEX", "TEST"];
|
||||
|
||||
const hashSymbol = (value: string): number => {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < value.length; i += 1) {
|
||||
hash = (hash * 31 + value.charCodeAt(i)) >>> 0;
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
|
||||
const buildSyntheticPrint = (
|
||||
seq: number,
|
||||
now: number,
|
||||
symbol: string,
|
||||
price: number,
|
||||
size: number,
|
||||
exchange: string,
|
||||
offExchangeFlag: boolean
|
||||
): EquityPrint => {
|
||||
return {
|
||||
source_ts: now,
|
||||
ingest_ts: now,
|
||||
seq,
|
||||
trace_id: `ingest-equities-${seq}`,
|
||||
trace_id: `synthetic-equities-${seq}`,
|
||||
ts: now,
|
||||
underlying_id: "SPY",
|
||||
price: 450.1,
|
||||
size: 100,
|
||||
exchange: "TEST",
|
||||
offExchangeFlag: false
|
||||
underlying_id: symbol,
|
||||
price,
|
||||
size,
|
||||
exchange,
|
||||
offExchangeFlag
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -35,10 +53,21 @@ export const createSyntheticEquitiesAdapter = (
|
|||
return;
|
||||
}
|
||||
|
||||
seq += 1;
|
||||
const now = Date.now();
|
||||
const print = buildSyntheticPrint(seq, now);
|
||||
const batchSize = 3;
|
||||
|
||||
for (let i = 0; i < batchSize; i += 1) {
|
||||
seq += 1;
|
||||
const symbol = SP500_SYMBOLS[(seq + i) % SP500_SYMBOLS.length];
|
||||
const symbolHash = hashSymbol(symbol);
|
||||
const basePrice = 25 + (symbolHash % 475);
|
||||
const price = Number((basePrice + ((seq % 40) - 20) * 0.05).toFixed(2));
|
||||
const size = 10 + (seq % 600);
|
||||
const exchange = EXCHANGES[(seq + symbolHash) % EXCHANGES.length];
|
||||
const offExchangeFlag = (seq + i) % 6 === 0;
|
||||
const print = buildSyntheticPrint(seq, now + i * 4, symbol, price, size, exchange, offExchangeFlag);
|
||||
void handlers.onTrade(print);
|
||||
}
|
||||
};
|
||||
|
||||
timer = setInterval(emit, config.emitIntervalMs);
|
||||
|
|
|
|||
|
|
@ -1,22 +1,72 @@
|
|||
import type { OptionPrint } from "@islandflow/types";
|
||||
import { SP500_SYMBOLS, type OptionPrint } from "@islandflow/types";
|
||||
import type { OptionIngestAdapter, OptionIngestHandlers } from "./types";
|
||||
|
||||
type SyntheticOptionsAdapterConfig = {
|
||||
emitIntervalMs: number;
|
||||
};
|
||||
|
||||
const buildSyntheticPrint = (seq: number, now: number): OptionPrint => {
|
||||
type Burst = {
|
||||
contractId: string;
|
||||
basePrice: number;
|
||||
baseSize: number;
|
||||
exchange: string;
|
||||
conditions?: string[];
|
||||
burstSize: number;
|
||||
};
|
||||
|
||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
const EXPIRY_OFFSETS = [7, 14, 28, 45, 60, 90];
|
||||
const EXCHANGES = ["CBOE", "PHLX", "ISE", "ARCA", "BOX", "MIAX"];
|
||||
const CONDITIONS = ["SWEEP", "ISO", "FILL", "TEST"];
|
||||
|
||||
const pick = <T,>(items: T[], seed: number): T => {
|
||||
return items[Math.abs(seed) % items.length];
|
||||
};
|
||||
|
||||
const hashSymbol = (value: string): number => {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < value.length; i += 1) {
|
||||
hash = (hash * 31 + value.charCodeAt(i)) >>> 0;
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
|
||||
const formatStrike = (strike: number): string => {
|
||||
const fixed = strike.toFixed(3);
|
||||
return fixed.replace(/\.?0+$/, "");
|
||||
};
|
||||
|
||||
const formatExpiry = (now: number, offsetDays: number): string => {
|
||||
const expiryDate = new Date(now + offsetDays * MS_PER_DAY);
|
||||
return expiryDate.toISOString().slice(0, 10);
|
||||
};
|
||||
|
||||
const buildBurst = (burstIndex: number, now: number): Burst => {
|
||||
const symbol = SP500_SYMBOLS[burstIndex % SP500_SYMBOLS.length];
|
||||
const symbolHash = hashSymbol(symbol);
|
||||
const basePrice = 30 + (symbolHash % 470);
|
||||
const expiryOffset = pick(EXPIRY_OFFSETS, symbolHash + burstIndex);
|
||||
const expiry = formatExpiry(now, expiryOffset);
|
||||
const strikeStep = basePrice >= 200 ? 10 : 5;
|
||||
const strikeOffset = ((burstIndex % 7) - 3) * strikeStep;
|
||||
const strike = Math.max(1, Math.round(basePrice / strikeStep) * strikeStep + strikeOffset);
|
||||
const right = burstIndex % 2 === 0 ? "C" : "P";
|
||||
const contractId = `${symbol}-${expiry}-${formatStrike(strike)}-${right}`;
|
||||
const exchange = pick(EXCHANGES, burstIndex + symbolHash);
|
||||
const isBlock = burstIndex % 4 === 0;
|
||||
const burstSize = isBlock ? 4 : burstIndex % 3 === 0 ? 2 : 1;
|
||||
const baseSize = isBlock ? 1200 + (symbolHash % 1800) : 5 + (symbolHash % 180);
|
||||
const distance = Math.abs(strike - basePrice);
|
||||
const basePricePer = isBlock ? 12 + distance / strikeStep : 0.5 + distance / 30;
|
||||
const conditions = isBlock ? [pick(CONDITIONS, burstIndex)] : undefined;
|
||||
|
||||
return {
|
||||
source_ts: now,
|
||||
ingest_ts: now,
|
||||
seq,
|
||||
trace_id: `ingest-options-${seq}`,
|
||||
ts: now,
|
||||
option_contract_id: "SPY-2025-01-17-450-C",
|
||||
price: 1.25,
|
||||
size: 10,
|
||||
exchange: "TEST",
|
||||
conditions: ["TEST"]
|
||||
contractId,
|
||||
basePrice: basePricePer,
|
||||
baseSize,
|
||||
exchange,
|
||||
conditions,
|
||||
burstSize
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -27,6 +77,9 @@ export const createSyntheticOptionsAdapter = (
|
|||
name: "synthetic",
|
||||
start: (handlers: OptionIngestHandlers) => {
|
||||
let seq = 0;
|
||||
let burstIndex = 0;
|
||||
let currentBurst: Burst | null = null;
|
||||
let remaining = 0;
|
||||
let timer: ReturnType<typeof setInterval> | null = null;
|
||||
let stopped = false;
|
||||
|
||||
|
|
@ -35,10 +88,37 @@ export const createSyntheticOptionsAdapter = (
|
|||
return;
|
||||
}
|
||||
|
||||
seq += 1;
|
||||
const now = Date.now();
|
||||
const print = buildSyntheticPrint(seq, now);
|
||||
if (!currentBurst || remaining <= 0) {
|
||||
burstIndex += 1;
|
||||
currentBurst = buildBurst(burstIndex, now);
|
||||
remaining = currentBurst.burstSize;
|
||||
}
|
||||
|
||||
const burst = currentBurst;
|
||||
const printsToEmit = remaining;
|
||||
|
||||
for (let i = 0; i < printsToEmit; i += 1) {
|
||||
seq += 1;
|
||||
const priceJitter = (i % 3) - 1;
|
||||
const sizeJitter = (i % 4) - 1;
|
||||
const print: OptionPrint = {
|
||||
source_ts: now + i * 5,
|
||||
ingest_ts: now + i * 5,
|
||||
seq,
|
||||
trace_id: `synthetic-options-${seq}`,
|
||||
ts: now + i * 5,
|
||||
option_contract_id: burst.contractId,
|
||||
price: Math.max(0.05, Number((burst.basePrice * (1 + priceJitter * 0.02)).toFixed(2))),
|
||||
size: Math.max(1, Math.round(burst.baseSize * (1 + sizeJitter * 0.05))),
|
||||
exchange: burst.exchange,
|
||||
conditions: burst.conditions
|
||||
};
|
||||
|
||||
void handlers.onTrade(print);
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
};
|
||||
|
||||
timer = setInterval(emit, config.emitIntervalMs);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue