This commit is contained in:
parent
65139bf8d0
commit
44431c4e66
71 changed files with 2262 additions and 1173 deletions
|
|
@ -85,10 +85,14 @@ const decodePayload = (data: WebSocket.RawData): unknown => {
|
|||
}
|
||||
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
return JSON.parse(new TextDecoder().decode(new Uint8Array(data.buffer, data.byteOffset, data.byteLength))) as unknown;
|
||||
return JSON.parse(
|
||||
new TextDecoder().decode(new Uint8Array(data.buffer, data.byteOffset, data.byteLength))
|
||||
) as unknown;
|
||||
}
|
||||
|
||||
return JSON.parse(new TextDecoder().decode(new Uint8Array(data as unknown as ArrayBuffer))) as unknown;
|
||||
return JSON.parse(
|
||||
new TextDecoder().decode(new Uint8Array(data as unknown as ArrayBuffer))
|
||||
) as unknown;
|
||||
};
|
||||
|
||||
const extractExchangeMeta = (payload: unknown): AlpacaExchangeMetaEntry[] => {
|
||||
|
|
@ -103,8 +107,18 @@ const extractExchangeMeta = (payload: unknown): AlpacaExchangeMetaEntry[] => {
|
|||
continue;
|
||||
}
|
||||
const candidate = entry as Record<string, unknown>;
|
||||
const code = typeof candidate.code === "string" ? candidate.code : typeof candidate.exchange === "string" ? candidate.exchange : null;
|
||||
const name = typeof candidate.name === "string" ? candidate.name : typeof candidate.description === "string" ? candidate.description : null;
|
||||
const code =
|
||||
typeof candidate.code === "string"
|
||||
? candidate.code
|
||||
: typeof candidate.exchange === "string"
|
||||
? candidate.exchange
|
||||
: null;
|
||||
const name =
|
||||
typeof candidate.name === "string"
|
||||
? candidate.name
|
||||
: typeof candidate.description === "string"
|
||||
? candidate.description
|
||||
: null;
|
||||
if (!code || !name) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -128,9 +142,19 @@ const buildExchangeNameMap = (entries: AlpacaExchangeMetaEntry[]): Map<string, s
|
|||
return map;
|
||||
};
|
||||
|
||||
const OFF_EXCHANGE_HINTS = ["FINRA", "TRF", "ADF", "OTC", "Trade Reporting Facility", "Alternative Display Facility"];
|
||||
const OFF_EXCHANGE_HINTS = [
|
||||
"FINRA",
|
||||
"TRF",
|
||||
"ADF",
|
||||
"OTC",
|
||||
"Trade Reporting Facility",
|
||||
"Alternative Display Facility"
|
||||
];
|
||||
|
||||
export const inferOffExchangeFlag = (exchangeCode: string | undefined, exchangeNameMap: Map<string, string>): boolean => {
|
||||
export const inferOffExchangeFlag = (
|
||||
exchangeCode: string | undefined,
|
||||
exchangeNameMap: Map<string, string>
|
||||
): boolean => {
|
||||
if (!exchangeCode) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -151,7 +175,9 @@ const buildWsUrl = (wsBaseUrl: string, feed: AlpacaEquitiesFeed): string => {
|
|||
return `${parsed.origin}/v2/${feed}`;
|
||||
};
|
||||
|
||||
const fetchExchangeMeta = async (config: AlpacaEquitiesAdapterConfig): Promise<Map<string, string>> => {
|
||||
const fetchExchangeMeta = async (
|
||||
config: AlpacaEquitiesAdapterConfig
|
||||
): Promise<Map<string, string>> => {
|
||||
const url = new URL("/v2/stocks/meta/exchanges", config.restUrl);
|
||||
|
||||
try {
|
||||
|
|
@ -243,7 +269,10 @@ export const createAlpacaEquitiesAdapter = (
|
|||
continue;
|
||||
}
|
||||
|
||||
const message = entry as (AlpacaTradeMessage | AlpacaQuoteMessage | { T?: string; msg?: string });
|
||||
const message = entry as
|
||||
| AlpacaTradeMessage
|
||||
| AlpacaQuoteMessage
|
||||
| { T?: string; msg?: string };
|
||||
const type = message.T;
|
||||
|
||||
if (type === "success") {
|
||||
|
|
|
|||
|
|
@ -89,11 +89,7 @@ const priceForPlacement = (
|
|||
return formatPrice(Math.max(0.01, price));
|
||||
};
|
||||
|
||||
const buildQuoteContext = (
|
||||
symbol: string,
|
||||
now: number,
|
||||
control: SyntheticControlState
|
||||
) => {
|
||||
const buildQuoteContext = (symbol: string, now: number, control: SyntheticControlState) => {
|
||||
const session = getSyntheticSessionState(now, control);
|
||||
const state = getSyntheticUnderlyingState(symbol, now, control, session);
|
||||
return {
|
||||
|
|
@ -184,7 +180,9 @@ export const createSyntheticEquitiesAdapter = (
|
|||
session.regime === "retail_chase";
|
||||
|
||||
if (allowDark) {
|
||||
const darkSymbol = focusSymbols[seq % focusSymbols.length] ?? SYNTHETIC_SYMBOLS[symbolCursor % SYNTHETIC_SYMBOLS.length]!;
|
||||
const darkSymbol =
|
||||
focusSymbols[seq % focusSymbols.length] ??
|
||||
SYNTHETIC_SYMBOLS[symbolCursor % SYNTHETIC_SYMBOLS.length]!;
|
||||
const darkQuote = buildQuoteContext(darkSymbol, now, control);
|
||||
const darkPlacement = pickDarkPlacement(
|
||||
darkQuote.state.driftBps,
|
||||
|
|
@ -203,13 +201,7 @@ export const createSyntheticEquitiesAdapter = (
|
|||
if (handlers.onQuote) {
|
||||
quoteSeq += 1;
|
||||
void handlers.onQuote(
|
||||
buildSyntheticQuote(
|
||||
quoteSeq,
|
||||
now - 2,
|
||||
darkSymbol,
|
||||
darkQuote.bid,
|
||||
darkQuote.ask
|
||||
)
|
||||
buildSyntheticQuote(quoteSeq, now - 2, darkSymbol, darkQuote.bid, darkQuote.ask)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -236,11 +228,7 @@ export const createSyntheticEquitiesAdapter = (
|
|||
const eventTs = now + i * 4;
|
||||
const quote = buildQuoteContext(symbol, eventTs, control);
|
||||
const clustered = focusSet.has(symbol);
|
||||
const placement = pickPrimaryPlacement(
|
||||
quote.state.driftBps,
|
||||
session.regime,
|
||||
seq + i
|
||||
);
|
||||
const placement = pickPrimaryPlacement(quote.state.driftBps, session.regime, seq + i);
|
||||
const exchange = EXCHANGES[(seq + symbol.charCodeAt(0) + i) % EXCHANGES.length]!;
|
||||
const baseSize =
|
||||
throughput.litSizeBase +
|
||||
|
|
@ -255,13 +243,7 @@ export const createSyntheticEquitiesAdapter = (
|
|||
if (handlers.onQuote) {
|
||||
quoteSeq += 1;
|
||||
void handlers.onQuote(
|
||||
buildSyntheticQuote(
|
||||
quoteSeq,
|
||||
eventTs - 2,
|
||||
symbol,
|
||||
quote.bid,
|
||||
quote.ask
|
||||
)
|
||||
buildSyntheticQuote(quoteSeq, eventTs - 2, symbol, quote.bid, quote.ask)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue