added more functions
This commit is contained in:
parent
a1c82ae0b8
commit
cca9ac03dd
8 changed files with 1563 additions and 2 deletions
|
|
@ -664,8 +664,293 @@ export function volumeConcentrationHHI(
|
|||
|
||||
return hhi * 10000; // Scale to 0-10000 range
|
||||
}
|
||||
/**
|
||||
* Volume Profile
|
||||
*/
|
||||
export function volumeProfile(
|
||||
ohlcv: OHLCVData[],
|
||||
priceLevels: number
|
||||
): { [price: number]: number } {
|
||||
const profile: { [price: number]: number } = {};
|
||||
|
||||
// Helper functions
|
||||
if (ohlcv.length === 0) return profile;
|
||||
|
||||
const minPrice = Math.min(...ohlcv.map(candle => candle.low));
|
||||
const maxPrice = Math.max(...ohlcv.map(candle => candle.high));
|
||||
const priceRange = maxPrice - minPrice;
|
||||
const priceIncrement = priceRange / priceLevels;
|
||||
|
||||
for (let i = 0; i < priceLevels; i++) {
|
||||
const priceLevel = minPrice + i * priceIncrement;
|
||||
profile[priceLevel] = 0;
|
||||
}
|
||||
|
||||
for (const candle of ohlcv) {
|
||||
const typicalPrice = (candle.high + candle.low + candle.close) / 3;
|
||||
const priceLevel = minPrice + Math.floor((typicalPrice - minPrice) / priceIncrement) * priceIncrement;
|
||||
if (profile[priceLevel] !== undefined) {
|
||||
profile[priceLevel] += candle.volume;
|
||||
}
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delta Neutral Hedging Ratio
|
||||
*/
|
||||
export function deltaNeutralHedgingRatio(
|
||||
optionDelta: number
|
||||
): number {
|
||||
return -optionDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gamma Scalping Range
|
||||
*/
|
||||
export function gammaScalpingRange(
|
||||
gamma: number,
|
||||
theta: number,
|
||||
timeIncrement: number
|
||||
): number {
|
||||
return Math.sqrt(2 * Math.abs(theta) * timeIncrement / gamma);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimal Order Size (based on market impact)
|
||||
*/
|
||||
export function optimalOrderSize(
|
||||
alpha: number,
|
||||
lambda: number
|
||||
): number {
|
||||
return alpha / (2 * lambda);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adverse Selection Component of the Spread
|
||||
*/
|
||||
export function adverseSelectionComponent(
|
||||
probabilityOfInformedTrader: number,
|
||||
spread: number
|
||||
): number {
|
||||
return probabilityOfInformedTrader * spread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inventory Risk Component of the Spread
|
||||
*/
|
||||
export function inventoryRiskComponent(
|
||||
inventoryHoldingCost: number,
|
||||
orderArrivalRate: number
|
||||
): number {
|
||||
return inventoryHoldingCost * Math.sqrt(orderArrivalRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quote Age
|
||||
*/
|
||||
export function quoteAge(
|
||||
lastUpdate: Date
|
||||
): number {
|
||||
return Date.now() - lastUpdate.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trade Classification (Lee-Ready algorithm)
|
||||
*/
|
||||
export function tradeClassification(
|
||||
tradePrice: number,
|
||||
bidPrice: number,
|
||||
askPrice: number,
|
||||
previousTradePrice: number
|
||||
): 'buy' | 'sell' | 'unknown' {
|
||||
if (tradePrice > askPrice) {
|
||||
return 'buy';
|
||||
} else if (tradePrice < bidPrice) {
|
||||
return 'sell';
|
||||
} else if (tradePrice >= previousTradePrice) {
|
||||
return 'buy';
|
||||
} else {
|
||||
return 'sell';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tick Rule
|
||||
*/
|
||||
export function tickRule(
|
||||
tradePrice: number,
|
||||
previousTradePrice: number
|
||||
): 'buy' | 'sell' | 'unknown' {
|
||||
if (tradePrice > previousTradePrice) {
|
||||
return 'buy';
|
||||
} else if (tradePrice < previousTradePrice) {
|
||||
return 'sell';
|
||||
} else {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Amihud's Lambda Variation with High-Frequency Data
|
||||
*/
|
||||
export function amihudIlliquidityHFT(
|
||||
priceChanges: number[],
|
||||
dollarVolumes: number[],
|
||||
timeDeltas: number[]
|
||||
): number {
|
||||
let illiquiditySum = 0;
|
||||
let validTrades = 0;
|
||||
|
||||
for (let i = 0; i < priceChanges.length; i++) {
|
||||
if (dollarVolumes[i] > 0 && timeDeltas[i] > 0) {
|
||||
illiquiditySum += Math.abs(priceChanges[i]) / (dollarVolumes[i] * timeDeltas[i]);
|
||||
validTrades++;
|
||||
}
|
||||
}
|
||||
|
||||
return validTrades > 0 ? illiquiditySum / validTrades : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parkinson Volatility
|
||||
*/
|
||||
export function parkinsonVolatility(
|
||||
highPrices: number[],
|
||||
lowPrices: number[]
|
||||
): number {
|
||||
if (highPrices.length !== lowPrices.length || highPrices.length < 2) return 0;
|
||||
|
||||
let sumSquaredLogHL = 0;
|
||||
for (let i = 0; i < highPrices.length; i++) {
|
||||
const logHL = Math.log(highPrices[i] / lowPrices[i]);
|
||||
sumSquaredLogHL += logHL * logHL;
|
||||
}
|
||||
|
||||
const parkinsonVariance = (1 / (4 * highPrices.length * Math.log(2))) * sumSquaredLogHL;
|
||||
return Math.sqrt(parkinsonVariance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Garman-Klass Volatility
|
||||
*/
|
||||
export function garmanKlassVolatility(
|
||||
openPrices: number[],
|
||||
highPrices: number[],
|
||||
lowPrices: number[],
|
||||
closePrices: number[]
|
||||
): number {
|
||||
if (openPrices.length !== highPrices.length || openPrices.length !== lowPrices.length || openPrices.length !== closePrices.length || openPrices.length < 2) return 0;
|
||||
|
||||
let sumSquaredTerm1 = 0;
|
||||
let sumSquaredTerm2 = 0;
|
||||
let sumSquaredTerm3 = 0;
|
||||
|
||||
for (let i = 0; i < openPrices.length; i++) {
|
||||
const logHO = Math.log(highPrices[i] / openPrices[i]);
|
||||
const logLO = Math.log(lowPrices[i] / openPrices[i]);
|
||||
const logCO = Math.log(closePrices[i] / openPrices[i]);
|
||||
|
||||
sumSquaredTerm1 += 0.5 * (logHO * logHO + logLO * logLO);
|
||||
sumSquaredTerm2 += - (2 * Math.log(2) - 1) * (logCO * logCO);
|
||||
}
|
||||
|
||||
const garmanKlassVariance = (1 / openPrices.length) * (sumSquaredTerm1 + sumSquaredTerm2);
|
||||
return Math.sqrt(garmanKlassVariance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Yang-Zhang Volatility
|
||||
*/
|
||||
export function yangZhangVolatility(
|
||||
openPrices: number[],
|
||||
highPrices: number[],
|
||||
lowPrices: number[],
|
||||
closePrices: number[],
|
||||
previousClosePrices: number[]
|
||||
): number {
|
||||
if (openPrices.length !== highPrices.length || openPrices.length !== lowPrices.length || openPrices.length !== closePrices.length || openPrices.length !== previousClosePrices.length || openPrices.length < 2) return 0;
|
||||
|
||||
const k = 0.34 / (1.34 + (openPrices.length + 1) / (previousClosePrices.length - 1));
|
||||
|
||||
let sumSquaredTerm1 = 0;
|
||||
let sumSquaredTerm2 = 0;
|
||||
let sumSquaredTerm3 = 0;
|
||||
|
||||
for (let i = 0; i < openPrices.length; i++) {
|
||||
const overnightReturn = Math.log(openPrices[i] / previousClosePrices[i]);
|
||||
const openToHigh = Math.log(highPrices[i] / openPrices[i]);
|
||||
const openToLow = Math.log(lowPrices[i] / openPrices[i]);
|
||||
const closeToOpen = Math.log(closePrices[i] / openPrices[i]);
|
||||
|
||||
sumSquaredTerm1 += overnightReturn * overnightReturn;
|
||||
sumSquaredTerm2 += openToHigh * openToHigh;
|
||||
sumSquaredTerm3 += openToLow * openToLow;
|
||||
}
|
||||
|
||||
const variance = sumSquaredTerm1 + k * sumSquaredTerm2 + (1 - k) * sumSquaredTerm3;
|
||||
return Math.sqrt(variance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Volume Order Imbalance (VOI)
|
||||
*/
|
||||
export function volumeOrderImbalance(
|
||||
buyVolumes: number[],
|
||||
sellVolumes: number[]
|
||||
): number[] {
|
||||
if (buyVolumes.length !== sellVolumes.length) return [];
|
||||
|
||||
const voi: number[] = [];
|
||||
for (let i = 0; i < buyVolumes.length; i++) {
|
||||
voi.push(buyVolumes[i] - sellVolumes[i]);
|
||||
}
|
||||
return voi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cumulative Volume Delta (CVD)
|
||||
*/
|
||||
export function cumulativeVolumeDelta(
|
||||
buyVolumes: number[],
|
||||
sellVolumes: number[]
|
||||
): number[] {
|
||||
if (buyVolumes.length !== sellVolumes.length) return [];
|
||||
|
||||
const cvd: number[] = [];
|
||||
let cumulativeDelta = 0;
|
||||
for (let i = 0; i < buyVolumes.length; i++) {
|
||||
cumulativeDelta += buyVolumes[i] - sellVolumes[i];
|
||||
cvd.push(cumulativeDelta);
|
||||
}
|
||||
return cvd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Market Order Ratio
|
||||
*/
|
||||
export function marketOrderRatio(
|
||||
marketOrders: number[],
|
||||
limitOrders: number[]
|
||||
): number[] {
|
||||
if (marketOrders.length !== limitOrders.length) return [];
|
||||
|
||||
const ratios: number[] = [];
|
||||
for (let i = 0; i < marketOrders.length; i++) {
|
||||
const totalOrders = marketOrders[i] + limitOrders[i];
|
||||
ratios.push(totalOrders > 0 ? marketOrders[i] / totalOrders : 0);
|
||||
}
|
||||
return ratios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to calculate the average of an array of numbers
|
||||
*/
|
||||
|
||||
function average(arr: number[]): number {
|
||||
if (arr.length === 0) return 0;
|
||||
return arr.reduce((a, b) => a + b, 0) / arr.length;
|
||||
}
|
||||
|
||||
function calculateVolatility(returns: number[]): number {
|
||||
if (returns.length < 2) return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue