added more functions
This commit is contained in:
parent
a53d8d13ca
commit
a1c82ae0b8
7 changed files with 648 additions and 177 deletions
|
|
@ -326,10 +326,9 @@ export function IntradayPatterns(
|
|||
hourlyVolume[hour] = data.volumes.length > 0 ?
|
||||
data.volumes.reduce((sum, vol) => sum + vol, 0) / data.volumes.length : 0;
|
||||
}
|
||||
|
||||
// opening gap and closing drift
|
||||
// opening gap and closing drift
|
||||
const openingGap = ohlcv.length > 1 ?
|
||||
(ohlcv[0].open - ohlcv[0].close) / ohlcv[0].close : 0;
|
||||
(ohlcv[1].open - ohlcv[0].close) / ohlcv[0].close : 0;
|
||||
|
||||
const lastCandle = ohlcv[ohlcv.length - 1];
|
||||
const closingDrift = (lastCandle.close - lastCandle.open) / lastCandle.open;
|
||||
|
|
@ -536,6 +535,136 @@ export function ImplementationShortfall(
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Amihud Illiquidity Measure (price impact per unit of volume)
|
||||
*/
|
||||
export function amihudIlliquidity(
|
||||
ohlcv: OHLCVData[],
|
||||
lookbackPeriod: number = 252
|
||||
): number {
|
||||
if (ohlcv.length < lookbackPeriod) return 0;
|
||||
|
||||
const recentData = ohlcv.slice(-lookbackPeriod);
|
||||
let illiquiditySum = 0;
|
||||
let validDays = 0;
|
||||
|
||||
for (const candle of recentData) {
|
||||
if (candle.volume > 0) {
|
||||
const dailyReturn = Math.abs((candle.close - candle.open) / candle.open);
|
||||
const dollarVolume = candle.volume * candle.close;
|
||||
|
||||
if (dollarVolume > 0) {
|
||||
illiquiditySum += dailyReturn / dollarVolume;
|
||||
validDays++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validDays > 0 ? (illiquiditySum / validDays) * 1000000 : 0; // Scale to millions
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll's Spread Estimator (effective spread from serial covariance)
|
||||
*/
|
||||
export function rollSpreadEstimator(prices: number[]): number {
|
||||
if (prices.length < 3) return 0;
|
||||
|
||||
// Calculate price changes
|
||||
const priceChanges: number[] = [];
|
||||
for (let i = 1; i < prices.length; i++) {
|
||||
priceChanges.push(prices[i] - prices[i - 1]);
|
||||
}
|
||||
|
||||
// Calculate serial covariance
|
||||
let covariance = 0;
|
||||
for (let i = 1; i < priceChanges.length; i++) {
|
||||
covariance += priceChanges[i] * priceChanges[i - 1];
|
||||
}
|
||||
covariance /= (priceChanges.length - 1);
|
||||
|
||||
// Roll's estimator: spread = 2 * sqrt(-covariance)
|
||||
const spread = covariance < 0 ? 2 * Math.sqrt(-covariance) : 0;
|
||||
|
||||
return spread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kyle's Lambda (price impact coefficient)
|
||||
*/
|
||||
export function kyleLambda(
|
||||
priceChanges: number[],
|
||||
orderFlow: number[] // Signed order flow (positive for buys, negative for sells)
|
||||
): number {
|
||||
if (priceChanges.length !== orderFlow.length || priceChanges.length < 2) return 0;
|
||||
|
||||
// Calculate regression: priceChange = lambda * orderFlow + error
|
||||
const n = priceChanges.length;
|
||||
const meanPrice = priceChanges.reduce((sum, p) => sum + p, 0) / n;
|
||||
const meanFlow = orderFlow.reduce((sum, f) => sum + f, 0) / n;
|
||||
|
||||
let numerator = 0;
|
||||
let denominator = 0;
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const priceDeviation = priceChanges[i] - meanPrice;
|
||||
const flowDeviation = orderFlow[i] - meanFlow;
|
||||
|
||||
numerator += priceDeviation * flowDeviation;
|
||||
denominator += flowDeviation * flowDeviation;
|
||||
}
|
||||
|
||||
return denominator > 0 ? numerator / denominator : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probability of Informed Trading (PIN) - simplified version
|
||||
*/
|
||||
export function probabilityInformedTrading(
|
||||
buyVolumes: number[],
|
||||
sellVolumes: number[],
|
||||
period: number = 20
|
||||
): number {
|
||||
if (buyVolumes.length !== sellVolumes.length || buyVolumes.length < period) return 0;
|
||||
|
||||
const recentBuys = buyVolumes.slice(-period);
|
||||
const recentSells = sellVolumes.slice(-period);
|
||||
|
||||
let totalImbalance = 0;
|
||||
let totalVolume = 0;
|
||||
|
||||
for (let i = 0; i < period; i++) {
|
||||
const imbalance = Math.abs(recentBuys[i] - recentSells[i]);
|
||||
const volume = recentBuys[i] + recentSells[i];
|
||||
|
||||
totalImbalance += imbalance;
|
||||
totalVolume += volume;
|
||||
}
|
||||
|
||||
// Simplified PIN estimate based on order imbalance
|
||||
return totalVolume > 0 ? totalImbalance / totalVolume : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Herfindahl-Hirschman Index for Volume Concentration
|
||||
*/
|
||||
export function volumeConcentrationHHI(
|
||||
exchanges: Array<{ name: string; volume: number }>
|
||||
): number {
|
||||
if (exchanges.length === 0) return 0;
|
||||
|
||||
const totalVolume = exchanges.reduce((sum, exchange) => sum + exchange.volume, 0);
|
||||
|
||||
if (totalVolume === 0) return 0;
|
||||
|
||||
let hhi = 0;
|
||||
for (const exchange of exchanges) {
|
||||
const marketShare = exchange.volume / totalVolume;
|
||||
hhi += marketShare * marketShare;
|
||||
}
|
||||
|
||||
return hhi * 10000; // Scale to 0-10000 range
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
function calculateVolatility(returns: number[]): number {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue