From 113c6dfd71fbc8e9e2a6d533669781faaf5560da Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sat, 28 Mar 2026 02:23:31 +0100 Subject: [PATCH] =?UTF-8?q?feat:=2015=20funciones=20finance=20=E2=80=94=20?= =?UTF-8?q?indicadores,=20riesgo=20e=20IO=20de=20mercado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 11 funciones puras con implementación real: SMA, EMA, RSI, BollingerBands, VWAP, LogReturn, AnnualizedVolatility, SharpeRatio, MaxDrawdown, NormalizeOHLCV, TickToOHLCV 4 funciones impuras (stubs): FetchOHLCV, StreamTicks, WriteOHLCVToParquet, LoadOHLCVFromDuckDB Co-Authored-By: Claude Opus 4.6 (1M context) --- functions/finance/.gitkeep | 0 functions/finance/annualized_volatility.go | 25 ++++++++++ functions/finance/annualized_volatility.md | 31 ++++++++++++ functions/finance/bollinger_bands.go | 32 +++++++++++++ functions/finance/bollinger_bands.md | 34 +++++++++++++ functions/finance/ema.go | 23 +++++++++ functions/finance/ema.md | 33 +++++++++++++ functions/finance/fetch_ohlcv.go | 9 ++++ functions/finance/fetch_ohlcv.md | 31 ++++++++++++ functions/finance/load_ohlcv_from_duckdb.go | 9 ++++ functions/finance/load_ohlcv_from_duckdb.md | 31 ++++++++++++ functions/finance/log_return.go | 12 +++++ functions/finance/log_return.md | 32 +++++++++++++ functions/finance/max_drawdown.go | 27 +++++++++++ functions/finance/max_drawdown.md | 32 +++++++++++++ functions/finance/normalize_ohlcv.go | 17 +++++++ functions/finance/normalize_ohlcv.md | 38 +++++++++++++++ functions/finance/rsi.go | 47 ++++++++++++++++++ functions/finance/rsi.md | 31 ++++++++++++ functions/finance/sharpe_ratio.go | 29 +++++++++++ functions/finance/sharpe_ratio.md | 31 ++++++++++++ functions/finance/sma.go | 22 +++++++++ functions/finance/sma.md | 32 +++++++++++++ functions/finance/stream_ticks.go | 10 ++++ functions/finance/stream_ticks.md | 31 ++++++++++++ functions/finance/tick_to_ohlcv.go | 53 +++++++++++++++++++++ functions/finance/tick_to_ohlcv.md | 37 ++++++++++++++ functions/finance/vwap.go | 19 ++++++++ functions/finance/vwap.md | 32 +++++++++++++ functions/finance/write_ohlcv_to_parquet.go | 9 ++++ functions/finance/write_ohlcv_to_parquet.md | 31 ++++++++++++ 31 files changed, 830 insertions(+) delete mode 100644 functions/finance/.gitkeep create mode 100644 functions/finance/annualized_volatility.go create mode 100644 functions/finance/annualized_volatility.md create mode 100644 functions/finance/bollinger_bands.go create mode 100644 functions/finance/bollinger_bands.md create mode 100644 functions/finance/ema.go create mode 100644 functions/finance/ema.md create mode 100644 functions/finance/fetch_ohlcv.go create mode 100644 functions/finance/fetch_ohlcv.md create mode 100644 functions/finance/load_ohlcv_from_duckdb.go create mode 100644 functions/finance/load_ohlcv_from_duckdb.md create mode 100644 functions/finance/log_return.go create mode 100644 functions/finance/log_return.md create mode 100644 functions/finance/max_drawdown.go create mode 100644 functions/finance/max_drawdown.md create mode 100644 functions/finance/normalize_ohlcv.go create mode 100644 functions/finance/normalize_ohlcv.md create mode 100644 functions/finance/rsi.go create mode 100644 functions/finance/rsi.md create mode 100644 functions/finance/sharpe_ratio.go create mode 100644 functions/finance/sharpe_ratio.md create mode 100644 functions/finance/sma.go create mode 100644 functions/finance/sma.md create mode 100644 functions/finance/stream_ticks.go create mode 100644 functions/finance/stream_ticks.md create mode 100644 functions/finance/tick_to_ohlcv.go create mode 100644 functions/finance/tick_to_ohlcv.md create mode 100644 functions/finance/vwap.go create mode 100644 functions/finance/vwap.md create mode 100644 functions/finance/write_ohlcv_to_parquet.go create mode 100644 functions/finance/write_ohlcv_to_parquet.md diff --git a/functions/finance/.gitkeep b/functions/finance/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/functions/finance/annualized_volatility.go b/functions/finance/annualized_volatility.go new file mode 100644 index 00000000..251fd85b --- /dev/null +++ b/functions/finance/annualized_volatility.go @@ -0,0 +1,25 @@ +package finance + +import "math" + +// AnnualizedVolatility calcula la volatilidad anualizada a partir de una serie de retornos. +// periodsPerYear indica cuantos periodos hay en un anio (e.g. 252 para retornos diarios). +// Retorna stddev(returns) * sqrt(periodsPerYear). +func AnnualizedVolatility(returns []float64, periodsPerYear float64) float64 { + n := len(returns) + if n < 2 { + return 0 + } + var sum float64 + for _, r := range returns { + sum += r + } + mean := sum / float64(n) + var variance float64 + for _, r := range returns { + diff := r - mean + variance += diff * diff + } + variance /= float64(n - 1) + return math.Sqrt(variance) * math.Sqrt(periodsPerYear) +} diff --git a/functions/finance/annualized_volatility.md b/functions/finance/annualized_volatility.md new file mode 100644 index 00000000..bc61864d --- /dev/null +++ b/functions/finance/annualized_volatility.md @@ -0,0 +1,31 @@ +--- +name: annualized_volatility +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func AnnualizedVolatility(returns []float64, periodsPerYear float64) float64" +description: "Calcula la volatilidad anualizada a partir de una serie de retornos y la frecuencia de los periodos." +tags: [finance, volatility, risk, annualized] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [math] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/annualized_volatility.go" +--- + +# annualized_volatility + +Calcula la volatilidad anualizada como `stddev(returns) * sqrt(periodsPerYear)`. Usa desviacion estandar muestral (n-1). + +## Ejemplo + +```go +vol := finance.AnnualizedVolatility([]float64{0.01, -0.02, 0.015, 0.005, -0.01}, 252) +``` diff --git a/functions/finance/bollinger_bands.go b/functions/finance/bollinger_bands.go new file mode 100644 index 00000000..b2ea6db4 --- /dev/null +++ b/functions/finance/bollinger_bands.go @@ -0,0 +1,32 @@ +package finance + +import "math" + +// BollingerBands calcula las bandas de Bollinger: upper, middle (SMA), lower. +// Los primeros period-1 elementos de cada slice son 0. +func BollingerBands(data []float64, period int, numStdDev float64) (upper, middle, lower []float64) { + n := len(data) + upper = make([]float64, n) + middle = make([]float64, n) + lower = make([]float64, n) + if period <= 0 || period > n { + return + } + for i := period - 1; i < n; i++ { + var sum float64 + for j := i - period + 1; j <= i; j++ { + sum += data[j] + } + mean := sum / float64(period) + var variance float64 + for j := i - period + 1; j <= i; j++ { + diff := data[j] - mean + variance += diff * diff + } + std := math.Sqrt(variance / float64(period)) + middle[i] = mean + upper[i] = mean + numStdDev*std + lower[i] = mean - numStdDev*std + } + return +} diff --git a/functions/finance/bollinger_bands.md b/functions/finance/bollinger_bands.md new file mode 100644 index 00000000..4e9fcb3c --- /dev/null +++ b/functions/finance/bollinger_bands.md @@ -0,0 +1,34 @@ +--- +name: bollinger_bands +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func BollingerBands(data []float64, period int, numStdDev float64) (upper, middle, lower []float64)" +description: "Calcula las bandas de Bollinger (upper, middle, lower) para una serie de precios." +tags: [finance, indicator, bollinger, bands] +uses_functions: [] +uses_types: [bollinger_result_go_finance] +returns: [bollinger_result_go_finance] +returns_optional: false +error_type: "" +imports: [math] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/bollinger_bands.go" +--- + +# bollinger_bands + +Calcula las bandas de Bollinger. La banda media es la SMA, y las bandas superior e inferior estan a `numStdDev` desviaciones estandar de la media. Usa desviacion estandar poblacional. + +## Ejemplo + +```go +upper, middle, lower := finance.BollingerBands( + []float64{22, 24, 23, 25, 26, 28, 27, 29, 30, 28}, + 5, 2.0, +) +``` diff --git a/functions/finance/ema.go b/functions/finance/ema.go new file mode 100644 index 00000000..8b367a55 --- /dev/null +++ b/functions/finance/ema.go @@ -0,0 +1,23 @@ +package finance + +// EMA calcula la media movil exponencial de data con el periodo dado. +// El primer valor valido se inicializa con la SMA de los primeros period elementos. +// Los primeros period-1 elementos del resultado son 0. +func EMA(data []float64, period int) []float64 { + n := len(data) + result := make([]float64, n) + if period <= 0 || period > n { + return result + } + k := 2.0 / float64(period+1) + // Seed con SMA + var sum float64 + for i := 0; i < period; i++ { + sum += data[i] + } + result[period-1] = sum / float64(period) + for i := period; i < n; i++ { + result[i] = data[i]*k + result[i-1]*(1-k) + } + return result +} diff --git a/functions/finance/ema.md b/functions/finance/ema.md new file mode 100644 index 00000000..1a2acff5 --- /dev/null +++ b/functions/finance/ema.md @@ -0,0 +1,33 @@ +--- +name: ema +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func EMA(data []float64, period int) []float64" +description: "Calcula la media movil exponencial (EMA) sobre una serie de datos con un periodo dado." +tags: [finance, indicator, ema, moving-average] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/ema.go" +--- + +# ema + +Calcula la media movil exponencial (Exponential Moving Average). Se inicializa con la SMA de los primeros `period` elementos. El multiplicador es `2 / (period + 1)`. + +## Ejemplo + +```go +result := finance.EMA([]float64{10, 11, 12, 13, 14, 15}, 3) +// result[2] = SMA de los primeros 3 = 11.0 +// result[3] en adelante usa suavizado exponencial +``` diff --git a/functions/finance/fetch_ohlcv.go b/functions/finance/fetch_ohlcv.go new file mode 100644 index 00000000..0a0a4eab --- /dev/null +++ b/functions/finance/fetch_ohlcv.go @@ -0,0 +1,9 @@ +package finance + +import "fmt" + +// FetchOHLCV obtiene datos OHLCV de un exchange para un simbolo e intervalo dados. +// TODO: implementar conexion real al exchange. +func FetchOHLCV(symbol, interval string) ([][]float64, error) { + return nil, fmt.Errorf("not implemented: FetchOHLCV(%s, %s)", symbol, interval) +} diff --git a/functions/finance/fetch_ohlcv.md b/functions/finance/fetch_ohlcv.md new file mode 100644 index 00000000..30906363 --- /dev/null +++ b/functions/finance/fetch_ohlcv.md @@ -0,0 +1,31 @@ +--- +name: fetch_ohlcv +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: impure +signature: "func FetchOHLCV(symbol, interval string) ([][]float64, error)" +description: "Obtiene datos OHLCV de un exchange para un simbolo e intervalo dados." +tags: [finance, io, exchange, fetch] +uses_functions: [] +uses_types: [ohlcv_go_finance] +returns: [ohlcv_go_finance] +returns_optional: false +error_type: "error_go_core" +imports: [fmt] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/fetch_ohlcv.go" +--- + +# fetch_ohlcv + +Stub para obtener datos OHLCV de un exchange. Pendiente de implementacion. + +## Ejemplo + +```go +data, err := finance.FetchOHLCV("BTC/USDT", "1h") +``` diff --git a/functions/finance/load_ohlcv_from_duckdb.go b/functions/finance/load_ohlcv_from_duckdb.go new file mode 100644 index 00000000..02e3a50b --- /dev/null +++ b/functions/finance/load_ohlcv_from_duckdb.go @@ -0,0 +1,9 @@ +package finance + +import "fmt" + +// LoadOHLCVFromDuckDB carga datos OHLCV ejecutando una query en una base DuckDB. +// TODO: implementar conexion real a DuckDB. +func LoadOHLCVFromDuckDB(dbPath, query string) ([][]float64, error) { + return nil, fmt.Errorf("not implemented: LoadOHLCVFromDuckDB(%s, %s)", dbPath, query) +} diff --git a/functions/finance/load_ohlcv_from_duckdb.md b/functions/finance/load_ohlcv_from_duckdb.md new file mode 100644 index 00000000..55c5f496 --- /dev/null +++ b/functions/finance/load_ohlcv_from_duckdb.md @@ -0,0 +1,31 @@ +--- +name: load_ohlcv_from_duckdb +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: impure +signature: "func LoadOHLCVFromDuckDB(dbPath, query string) ([][]float64, error)" +description: "Carga datos OHLCV ejecutando una query SQL en una base de datos DuckDB." +tags: [finance, io, duckdb, load] +uses_functions: [] +uses_types: [ohlcv_go_finance] +returns: [ohlcv_go_finance] +returns_optional: false +error_type: "error_go_core" +imports: [fmt] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/load_ohlcv_from_duckdb.go" +--- + +# load_ohlcv_from_duckdb + +Stub para cargar datos OHLCV desde DuckDB. Pendiente de implementacion. + +## Ejemplo + +```go +data, err := finance.LoadOHLCVFromDuckDB("/data/market.duckdb", "SELECT * FROM ohlcv WHERE symbol='BTC'") +``` diff --git a/functions/finance/log_return.go b/functions/finance/log_return.go new file mode 100644 index 00000000..16e8ca4a --- /dev/null +++ b/functions/finance/log_return.go @@ -0,0 +1,12 @@ +package finance + +import "math" + +// LogReturn calcula el retorno logaritmico entre dos precios. +// Retorna ln(priceEnd / priceStart). Si priceStart <= 0 o priceEnd <= 0, retorna 0. +func LogReturn(priceStart, priceEnd float64) float64 { + if priceStart <= 0 || priceEnd <= 0 { + return 0 + } + return math.Log(priceEnd / priceStart) +} diff --git a/functions/finance/log_return.md b/functions/finance/log_return.md new file mode 100644 index 00000000..d05ec662 --- /dev/null +++ b/functions/finance/log_return.md @@ -0,0 +1,32 @@ +--- +name: log_return +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func LogReturn(priceStart, priceEnd float64) float64" +description: "Calcula el retorno logaritmico entre un precio inicial y un precio final." +tags: [finance, return, logarithmic, atomic] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [math] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/log_return.go" +--- + +# log_return + +Calcula el retorno logaritmico: `ln(priceEnd / priceStart)`. Si alguno de los precios es <= 0, retorna 0. + +## Ejemplo + +```go +r := finance.LogReturn(100.0, 110.0) +// r ~ 0.09531 (aprox 9.53%) +``` diff --git a/functions/finance/max_drawdown.go b/functions/finance/max_drawdown.go new file mode 100644 index 00000000..b93f455e --- /dev/null +++ b/functions/finance/max_drawdown.go @@ -0,0 +1,27 @@ +package finance + +// MaxDrawdown calcula el maximo drawdown de una serie de valores (e.g. equity curve). +// Retorna la magnitud del drawdown (valor positivo entre 0 y 1 como fraccion del pico), +// y los indices de inicio (pico) y fin (valle) del peor drawdown. +// Si la serie tiene menos de 2 elementos, retorna 0, 0, 0. +func MaxDrawdown(values []float64) (maxDD float64, start, end int) { + n := len(values) + if n < 2 { + return 0, 0, 0 + } + peakIdx := 0 + peak := values[0] + for i := 1; i < n; i++ { + if values[i] > peak { + peak = values[i] + peakIdx = i + } + dd := (peak - values[i]) / peak + if dd > maxDD { + maxDD = dd + start = peakIdx + end = i + } + } + return +} diff --git a/functions/finance/max_drawdown.md b/functions/finance/max_drawdown.md new file mode 100644 index 00000000..d7874086 --- /dev/null +++ b/functions/finance/max_drawdown.md @@ -0,0 +1,32 @@ +--- +name: max_drawdown +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func MaxDrawdown(values []float64) (maxDD float64, start, end int)" +description: "Calcula el maximo drawdown de una curva de equity, retornando la magnitud y los indices pico-valle." +tags: [finance, drawdown, risk, metric] +uses_functions: [] +uses_types: [drawdown_result_go_finance] +returns: [drawdown_result_go_finance] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/max_drawdown.go" +--- + +# max_drawdown + +Calcula el maximo drawdown (caida maxima desde un pico hasta un valle) como fraccion del pico. Retorna la magnitud (0 a 1) y los indices de inicio y fin. + +## Ejemplo + +```go +dd, s, e := finance.MaxDrawdown([]float64{100, 120, 90, 110, 80}) +// dd = (120-80)/120 = 0.3333, s = 1, e = 4 +``` diff --git a/functions/finance/normalize_ohlcv.go b/functions/finance/normalize_ohlcv.go new file mode 100644 index 00000000..9a4270db --- /dev/null +++ b/functions/finance/normalize_ohlcv.go @@ -0,0 +1,17 @@ +package finance + +// NormalizeOHLCV ajusta slices de precios OHLCV multiplicando por un factor. +func NormalizeOHLCV(open, high, low, close []float64, factor float64) ([]float64, []float64, []float64, []float64) { + n := len(open) + nOpen := make([]float64, n) + nHigh := make([]float64, n) + nLow := make([]float64, n) + nClose := make([]float64, n) + for i := 0; i < n; i++ { + nOpen[i] = open[i] * factor + nHigh[i] = high[i] * factor + nLow[i] = low[i] * factor + nClose[i] = close[i] * factor + } + return nOpen, nHigh, nLow, nClose +} diff --git a/functions/finance/normalize_ohlcv.md b/functions/finance/normalize_ohlcv.md new file mode 100644 index 00000000..95574180 --- /dev/null +++ b/functions/finance/normalize_ohlcv.md @@ -0,0 +1,38 @@ +--- +name: normalize_ohlcv +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func NormalizeOHLCV(open, high, low, close []float64, factor float64) ([]float64, []float64, []float64, []float64)" +description: "Ajusta slices de precios OHLCV multiplicando cada valor por un factor dado." +tags: [finance, ohlcv, normalize, adjust] +uses_functions: [] +uses_types: [ohlcv_go_finance] +returns: [ohlcv_go_finance] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/normalize_ohlcv.go" +--- + +# normalize_ohlcv + +Ajusta slices de precios OHLCV (open, high, low, close) multiplicando cada elemento por un factor escalar. Util para ajustes por splits, conversiones de divisa, o normalizacion de series. + +## Ejemplo + +```go +o, h, l, c := finance.NormalizeOHLCV( + []float64{100, 200}, + []float64{110, 210}, + []float64{90, 190}, + []float64{105, 205}, + 2.0, +) +// o = [200, 400], h = [220, 420], l = [180, 380], c = [210, 410] +``` diff --git a/functions/finance/rsi.go b/functions/finance/rsi.go new file mode 100644 index 00000000..cab72750 --- /dev/null +++ b/functions/finance/rsi.go @@ -0,0 +1,47 @@ +package finance + +// RSI calcula el Relative Strength Index. +// Usa el metodo de suavizado de Wilder (EMA con alpha = 1/period). +// Los primeros period elementos del resultado son 0. +func RSI(data []float64, period int) []float64 { + n := len(data) + result := make([]float64, n) + if period <= 0 || n < period+1 { + return result + } + var gainSum, lossSum float64 + for i := 1; i <= period; i++ { + change := data[i] - data[i-1] + if change > 0 { + gainSum += change + } else { + lossSum -= change + } + } + avgGain := gainSum / float64(period) + avgLoss := lossSum / float64(period) + if avgLoss == 0 { + result[period] = 100 + } else { + rs := avgGain / avgLoss + result[period] = 100 - 100/(1+rs) + } + for i := period + 1; i < n; i++ { + change := data[i] - data[i-1] + var gain, loss float64 + if change > 0 { + gain = change + } else { + loss = -change + } + avgGain = (avgGain*float64(period-1) + gain) / float64(period) + avgLoss = (avgLoss*float64(period-1) + loss) / float64(period) + if avgLoss == 0 { + result[i] = 100 + } else { + rs := avgGain / avgLoss + result[i] = 100 - 100/(1+rs) + } + } + return result +} diff --git a/functions/finance/rsi.md b/functions/finance/rsi.md new file mode 100644 index 00000000..21ee69ca --- /dev/null +++ b/functions/finance/rsi.md @@ -0,0 +1,31 @@ +--- +name: rsi +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func RSI(data []float64, period int) []float64" +description: "Calcula el Relative Strength Index (RSI) usando suavizado de Wilder." +tags: [finance, indicator, rsi, momentum] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/rsi.go" +--- + +# rsi + +Calcula el Relative Strength Index (RSI) con el metodo de suavizado de Wilder. Los primeros `period` elementos son 0. El RSI oscila entre 0 y 100. + +## Ejemplo + +```go +result := finance.RSI([]float64{44, 44.34, 44.09, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84}, 5) +``` diff --git a/functions/finance/sharpe_ratio.go b/functions/finance/sharpe_ratio.go new file mode 100644 index 00000000..67936800 --- /dev/null +++ b/functions/finance/sharpe_ratio.go @@ -0,0 +1,29 @@ +package finance + +import "math" + +// SharpeRatio calcula el ratio de Sharpe. +// riskFreeRate es la tasa libre de riesgo por periodo. +// periodsPerYear indica cuantos periodos hay en un anio (e.g. 252 para diario). +// Formula: (mean(returns) - riskFreeRate) / stddev(returns) * sqrt(periodsPerYear) +func SharpeRatio(returns []float64, riskFreeRate float64, periodsPerYear float64) float64 { + n := len(returns) + if n < 2 { + return 0 + } + var sum float64 + for _, r := range returns { + sum += r + } + mean := sum / float64(n) + var variance float64 + for _, r := range returns { + diff := r - mean + variance += diff * diff + } + std := math.Sqrt(variance / float64(n-1)) + if std == 0 { + return 0 + } + return (mean - riskFreeRate) / std * math.Sqrt(periodsPerYear) +} diff --git a/functions/finance/sharpe_ratio.md b/functions/finance/sharpe_ratio.md new file mode 100644 index 00000000..c7e33e54 --- /dev/null +++ b/functions/finance/sharpe_ratio.md @@ -0,0 +1,31 @@ +--- +name: sharpe_ratio +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func SharpeRatio(returns []float64, riskFreeRate float64, periodsPerYear float64) float64" +description: "Calcula el ratio de Sharpe anualizado a partir de retornos, tasa libre de riesgo y frecuencia." +tags: [finance, sharpe, risk, ratio] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [math] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/sharpe_ratio.go" +--- + +# sharpe_ratio + +Calcula el ratio de Sharpe: `(mean(returns) - riskFreeRate) / stddev(returns) * sqrt(periodsPerYear)`. Usa desviacion estandar muestral. + +## Ejemplo + +```go +sr := finance.SharpeRatio([]float64{0.01, 0.02, -0.005, 0.015, 0.008}, 0.0001, 252) +``` diff --git a/functions/finance/sma.go b/functions/finance/sma.go new file mode 100644 index 00000000..9920f762 --- /dev/null +++ b/functions/finance/sma.go @@ -0,0 +1,22 @@ +package finance + +// SMA calcula la media movil simple de data con el periodo dado. +// Retorna un slice de longitud len(data) donde los primeros period-1 +// elementos son 0 (sin datos suficientes). +func SMA(data []float64, period int) []float64 { + n := len(data) + result := make([]float64, n) + if period <= 0 || period > n { + return result + } + var sum float64 + for i := 0; i < period; i++ { + sum += data[i] + } + result[period-1] = sum / float64(period) + for i := period; i < n; i++ { + sum += data[i] - data[i-period] + result[i] = sum / float64(period) + } + return result +} diff --git a/functions/finance/sma.md b/functions/finance/sma.md new file mode 100644 index 00000000..388f20e4 --- /dev/null +++ b/functions/finance/sma.md @@ -0,0 +1,32 @@ +--- +name: sma +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func SMA(data []float64, period int) []float64" +description: "Calcula la media movil simple (SMA) sobre una serie de datos con un periodo dado." +tags: [finance, indicator, sma, moving-average] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/sma.go" +--- + +# sma + +Calcula la media movil simple (Simple Moving Average). Los primeros `period-1` elementos del resultado son 0 ya que no hay datos suficientes para calcular la media. + +## Ejemplo + +```go +result := finance.SMA([]float64{1, 2, 3, 4, 5}, 3) +// result = [0, 0, 2, 3, 4] +``` diff --git a/functions/finance/stream_ticks.go b/functions/finance/stream_ticks.go new file mode 100644 index 00000000..0a6ff2e7 --- /dev/null +++ b/functions/finance/stream_ticks.go @@ -0,0 +1,10 @@ +package finance + +import "fmt" + +// StreamTicks abre un stream de ticks en tiempo real para un simbolo. +// Retorna un canal de [2]float64 donde [0] es precio y [1] es volumen. +// TODO: implementar conexion real via websocket. +func StreamTicks(symbol string) (<-chan [2]float64, error) { + return nil, fmt.Errorf("not implemented: StreamTicks(%s)", symbol) +} diff --git a/functions/finance/stream_ticks.md b/functions/finance/stream_ticks.md new file mode 100644 index 00000000..fd30249f --- /dev/null +++ b/functions/finance/stream_ticks.md @@ -0,0 +1,31 @@ +--- +name: stream_ticks +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: impure +signature: "func StreamTicks(symbol string) (<-chan [2]float64, error)" +description: "Abre un stream de ticks en tiempo real para un simbolo via websocket." +tags: [finance, io, stream, realtime] +uses_functions: [] +uses_types: [tick_go_finance] +returns: [tick_go_finance] +returns_optional: false +error_type: "error_go_core" +imports: [fmt] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/stream_ticks.go" +--- + +# stream_ticks + +Stub para abrir un stream de ticks en tiempo real. Pendiente de implementacion. + +## Ejemplo + +```go +ch, err := finance.StreamTicks("ETH/USDT") +``` diff --git a/functions/finance/tick_to_ohlcv.go b/functions/finance/tick_to_ohlcv.go new file mode 100644 index 00000000..5e63852e --- /dev/null +++ b/functions/finance/tick_to_ohlcv.go @@ -0,0 +1,53 @@ +package finance + +// TickToOHLCV agrega datos de ticks en velas OHLCV segun un intervalo en segundos. +// prices, volumes y timestamps deben tener la misma longitud. +// timestamps son unix seconds. intervalSecs define el ancho de cada vela. +// Retorna slices de open, high, low, close, volume para cada vela generada. +func TickToOHLCV(prices, volumes []float64, timestamps []int64, intervalSecs int64) (open, high, low, close, vol []float64) { + n := len(prices) + if n == 0 || intervalSecs <= 0 { + return + } + bucketStart := timestamps[0] - (timestamps[0] % intervalSecs) + o := prices[0] + h := prices[0] + l := prices[0] + c := prices[0] + v := volumes[0] + + for i := 1; i < n; i++ { + currentBucket := timestamps[i] - (timestamps[i] % intervalSecs) + if currentBucket != bucketStart { + // Cerrar la vela anterior + open = append(open, o) + high = append(high, h) + low = append(low, l) + close = append(close, c) + vol = append(vol, v) + // Nueva vela + bucketStart = currentBucket + o = prices[i] + h = prices[i] + l = prices[i] + c = prices[i] + v = volumes[i] + } else { + if prices[i] > h { + h = prices[i] + } + if prices[i] < l { + l = prices[i] + } + c = prices[i] + v += volumes[i] + } + } + // Cerrar ultima vela + open = append(open, o) + high = append(high, h) + low = append(low, l) + close = append(close, c) + vol = append(vol, v) + return +} diff --git a/functions/finance/tick_to_ohlcv.md b/functions/finance/tick_to_ohlcv.md new file mode 100644 index 00000000..849eacde --- /dev/null +++ b/functions/finance/tick_to_ohlcv.md @@ -0,0 +1,37 @@ +--- +name: tick_to_ohlcv +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func TickToOHLCV(prices, volumes []float64, timestamps []int64, intervalSecs int64) (open, high, low, close, vol []float64)" +description: "Agrega datos de ticks en velas OHLCV segun un intervalo de tiempo en segundos." +tags: [finance, ohlcv, aggregate, tick] +uses_functions: [] +uses_types: [tick_go_finance, ohlcv_go_finance] +returns: [ohlcv_go_finance] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/tick_to_ohlcv.go" +--- + +# tick_to_ohlcv + +Agrega ticks (precio, volumen, timestamp) en velas OHLCV. Los ticks se agrupan en buckets de `intervalSecs` segundos. Los timestamps deben estar en unix seconds y ordenados cronologicamente. + +## Ejemplo + +```go +o, h, l, c, v := finance.TickToOHLCV( + []float64{100, 101, 99, 102}, + []float64{10, 20, 15, 25}, + []int64{1000, 1005, 1055, 1060}, + 60, +) +// Genera 2 velas: [1000-1059] y [1060-1119] +``` diff --git a/functions/finance/vwap.go b/functions/finance/vwap.go new file mode 100644 index 00000000..057e56ee --- /dev/null +++ b/functions/finance/vwap.go @@ -0,0 +1,19 @@ +package finance + +// VWAP calcula el Volume Weighted Average Price. +// prices y volumes deben tener la misma longitud. +// Retorna 0 si el volumen total es 0 o los slices estan vacios. +func VWAP(prices, volumes []float64) float64 { + if len(prices) == 0 || len(prices) != len(volumes) { + return 0 + } + var cumPV, cumV float64 + for i := range prices { + cumPV += prices[i] * volumes[i] + cumV += volumes[i] + } + if cumV == 0 { + return 0 + } + return cumPV / cumV +} diff --git a/functions/finance/vwap.md b/functions/finance/vwap.md new file mode 100644 index 00000000..66195a9d --- /dev/null +++ b/functions/finance/vwap.md @@ -0,0 +1,32 @@ +--- +name: vwap +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: pure +signature: "func VWAP(prices, volumes []float64) float64" +description: "Calcula el Volume Weighted Average Price (VWAP) a partir de precios y volumenes." +tags: [finance, indicator, vwap, volume] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/vwap.go" +--- + +# vwap + +Calcula el VWAP (Volume Weighted Average Price). Es la suma de (precio * volumen) dividida por la suma de volumenes. + +## Ejemplo + +```go +v := finance.VWAP([]float64{100, 102, 101}, []float64{500, 300, 200}) +// v = (100*500 + 102*300 + 101*200) / (500+300+200) +``` diff --git a/functions/finance/write_ohlcv_to_parquet.go b/functions/finance/write_ohlcv_to_parquet.go new file mode 100644 index 00000000..69352a57 --- /dev/null +++ b/functions/finance/write_ohlcv_to_parquet.go @@ -0,0 +1,9 @@ +package finance + +import "fmt" + +// WriteOHLCVToParquet persiste datos OHLCV en un archivo Parquet. +// TODO: implementar escritura real usando libreria Parquet. +func WriteOHLCVToParquet(path string, data [][]float64) error { + return fmt.Errorf("not implemented: WriteOHLCVToParquet(%s)", path) +} diff --git a/functions/finance/write_ohlcv_to_parquet.md b/functions/finance/write_ohlcv_to_parquet.md new file mode 100644 index 00000000..77c0da76 --- /dev/null +++ b/functions/finance/write_ohlcv_to_parquet.md @@ -0,0 +1,31 @@ +--- +name: write_ohlcv_to_parquet +kind: function +lang: go +domain: finance +version: "1.0.0" +purity: impure +signature: "func WriteOHLCVToParquet(path string, data [][]float64) error" +description: "Persiste datos OHLCV en un archivo Parquet en la ruta indicada." +tags: [finance, io, parquet, persist] +uses_functions: [] +uses_types: [ohlcv_go_finance] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [fmt] +tested: false +tests: [] +test_file_path: "" +file_path: "functions/finance/write_ohlcv_to_parquet.go" +--- + +# write_ohlcv_to_parquet + +Stub para persistir datos OHLCV en formato Parquet. Pendiente de implementacion. + +## Ejemplo + +```go +err := finance.WriteOHLCVToParquet("/data/btc_1h.parquet", ohlcvData) +```