fixed up types and working on utils lib
This commit is contained in:
parent
25d9f2dd85
commit
da75979574
17 changed files with 1093 additions and 901 deletions
191
libs/utils/src/generic-functions.ts
Normal file
191
libs/utils/src/generic-functions.ts
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/**
|
||||
* Generic utility functions that work with standardized types
|
||||
* These functions demonstrate how to use generic types with OHLCV data
|
||||
*/
|
||||
|
||||
import type { OHLCV, HasClose, HasOHLC, HasVolume } from '@stock-bot/types';
|
||||
|
||||
/**
|
||||
* Extract close prices from any data structure that has a close field
|
||||
* Works with OHLCV, MarketData, or any custom type with close price
|
||||
*/
|
||||
export function extractCloses<T extends HasClose>(data: T[]): number[] {
|
||||
return data.map(item => item.close);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract OHLC prices from any data structure that has OHLC fields
|
||||
*/
|
||||
export function extractOHLC<T extends HasOHLC>(data: T[]): {
|
||||
opens: number[];
|
||||
highs: number[];
|
||||
lows: number[];
|
||||
closes: number[];
|
||||
} {
|
||||
return {
|
||||
opens: data.map(item => item.open),
|
||||
highs: data.map(item => item.high),
|
||||
lows: data.map(item => item.low),
|
||||
closes: data.map(item => item.close),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract volumes from any data structure that has a volume field
|
||||
*/
|
||||
export function extractVolumes<T extends HasVolume>(data: T[]): number[] {
|
||||
return data.map(item => item.volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate simple moving average using close prices from any compatible data type
|
||||
*/
|
||||
export function calculateSMA<T extends HasClose>(data: T[], period: number): number[] {
|
||||
const closes = extractCloses(data);
|
||||
const result: number[] = [];
|
||||
|
||||
for (let i = period - 1; i < closes.length; i++) {
|
||||
const sum = closes.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
|
||||
result.push(sum / period);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate typical price (HLC/3) from any OHLC compatible data
|
||||
*/
|
||||
export function calculateTypicalPrice<T extends HasOHLC>(data: T[]): number[] {
|
||||
return data.map(item => (item.high + item.low + item.close) / 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate true range from OHLC data
|
||||
*/
|
||||
export function calculateTrueRange<T extends HasOHLC>(data: T[]): number[] {
|
||||
const result: number[] = [];
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (i === 0) {
|
||||
result.push(data[i]!.high - data[i]!.low);
|
||||
} else {
|
||||
const current = data[i]!;
|
||||
const previous = data[i - 1]!;
|
||||
const tr = Math.max(
|
||||
current.high - current.low,
|
||||
Math.abs(current.high - previous.close),
|
||||
Math.abs(current.low - previous.close)
|
||||
);
|
||||
result.push(tr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate returns from close prices
|
||||
*/
|
||||
export function calculateReturns<T extends HasClose>(data: T[]): number[] {
|
||||
const closes = extractCloses(data);
|
||||
const returns: number[] = [];
|
||||
|
||||
for (let i = 1; i < closes.length; i++) {
|
||||
const current = closes[i]!;
|
||||
const previous = closes[i - 1]!;
|
||||
if (previous > 0) {
|
||||
returns.push((current - previous) / previous);
|
||||
} else {
|
||||
returns.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
return returns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate log returns from close prices
|
||||
*/
|
||||
export function calculateLogReturns<T extends HasClose>(data: T[]): number[] {
|
||||
const closes = extractCloses(data);
|
||||
const logReturns: number[] = [];
|
||||
|
||||
for (let i = 1; i < closes.length; i++) {
|
||||
const current = closes[i]!;
|
||||
const previous = closes[i - 1]!;
|
||||
if (previous > 0 && current > 0) {
|
||||
logReturns.push(Math.log(current / previous));
|
||||
} else {
|
||||
logReturns.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
return logReturns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate volume-weighted average price (VWAP) from OHLC + Volume data
|
||||
*/
|
||||
export function calculateVWAP<T extends HasOHLC & HasVolume>(data: T[]): number[] {
|
||||
const result: number[] = [];
|
||||
let cumulativeVolumePrice = 0;
|
||||
let cumulativeVolume = 0;
|
||||
|
||||
for (const item of data) {
|
||||
const typicalPrice = (item.high + item.low + item.close) / 3;
|
||||
cumulativeVolumePrice += typicalPrice * item.volume;
|
||||
cumulativeVolume += item.volume;
|
||||
|
||||
if (cumulativeVolume > 0) {
|
||||
result.push(cumulativeVolumePrice / cumulativeVolume);
|
||||
} else {
|
||||
result.push(typicalPrice);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter OHLCV data by symbol
|
||||
*/
|
||||
export function filterBySymbol(data: OHLCV[], symbol: string): OHLCV[] {
|
||||
return data.filter(item => item.symbol === symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter OHLCV data by time range
|
||||
*/
|
||||
export function filterByTimeRange(
|
||||
data: OHLCV[],
|
||||
startTime: number,
|
||||
endTime: number
|
||||
): OHLCV[] {
|
||||
return data.filter(item => item.timestamp >= startTime && item.timestamp <= endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Group OHLCV data by symbol
|
||||
*/
|
||||
export function groupBySymbol(data: OHLCV[]): Record<string, OHLCV[]> {
|
||||
const grouped: Record<string, OHLCV[]> = {};
|
||||
|
||||
for (const item of data) {
|
||||
if (!grouped[item.symbol]) {
|
||||
grouped[item.symbol] = [];
|
||||
}
|
||||
grouped[item.symbol]!.push(item);
|
||||
}
|
||||
|
||||
return grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert timestamp to Date for OHLCV data
|
||||
*/
|
||||
export function convertTimestamps(data: OHLCV[]): Array<OHLCV & { date: Date }> {
|
||||
return data.map(item => ({
|
||||
...item,
|
||||
date: new Date(item.timestamp)
|
||||
}));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue