Packages

Trading technical indicators library for Gleam. SMA, EMA, MACD, RSI, Stochastic, Bollinger Bands, ATR, VWAP, OBV.

Current section

Files

Jump to
ursatoro src ursatoro@volatility.erl
Raw

src/ursatoro@volatility.erl

-module(ursatoro@volatility).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ursatoro/volatility.gleam").
-export([bollinger_bands/3, atr/2, har_volatility/4]).
-export_type([bollinger_bands_result/0, har_result/0]).
-type bollinger_bands_result() :: {bollinger_bands_result,
float(),
float(),
float()}.
-type har_result() :: {har_result, float(), float(), float(), float()}.
-file("src/ursatoro/volatility.gleam", 55).
-spec compute_bb(
gleam@deque:deque(bigdecimal:big_decimal()),
bigdecimal:big_decimal()
) -> bollinger_bands_result().
compute_bb(Window, Num_std) ->
Values = gleam@deque:to_list(Window),
Middle = case ursatoro@util:bd_mean(Values) of
{ok, M} ->
M;
{error, _} ->
bigdecimal:zero()
end,
Stddev = case ursatoro@util:bd_stddev_population(Values) of
{ok, S} ->
S;
{error, _} ->
bigdecimal:zero()
end,
Band_width = bigdecimal:multiply(Num_std, Stddev),
Upper = bigdecimal:add(Middle, Band_width),
Lower = bigdecimal:subtract(Middle, Band_width),
{bollinger_bands_result,
ursatoro@util:bd_to_float(Upper),
ursatoro@util:bd_to_float(Middle),
ursatoro@util:bd_to_float(Lower)}.
-file("src/ursatoro/volatility.gleam", 17).
-spec bollinger_bands(list(ursatoro@candle:candle()), integer(), float()) -> {ok,
list(bollinger_bands_result())} |
{error, ursatoro@util:indicator_error()}.
bollinger_bands(Candles, Period, Num_std) ->
gleam@result:'try'(
ursatoro@util:validate_period(Period),
fun(_) ->
gleam@result:'try'(
ursatoro@util:validate_length(Candles, Period),
fun(_) ->
Closes = gleam@list:map(
Candles,
fun ursatoro@candle:close/1
),
Num_std_bd = ursatoro@util:float_to_bd(Num_std),
{Results@1, _, _} = gleam@list:fold(
Closes,
{[], gleam@deque:new(), 0},
fun(Acc, Value) ->
{Results, Window, Count} = Acc,
New_window = gleam@deque:push_back(Window, Value),
New_count = Count + 1,
case New_count > Period of
true ->
case gleam@deque:pop_front(New_window) of
{ok, {_, Trimmed}} ->
Bb = compute_bb(Trimmed, Num_std_bd),
{[Bb | Results], Trimmed, Period};
{error, nil} ->
{Results, New_window, New_count}
end;
false ->
case New_count =:= Period of
true ->
Bb@1 = compute_bb(
New_window,
Num_std_bd
),
{[Bb@1 | Results],
New_window,
New_count};
false ->
{Results, New_window, New_count}
end
end
end
),
{ok, lists:reverse(Results@1)}
end
)
end
).
-file("src/ursatoro/volatility.gleam", 113).
-spec compute_true_ranges(list(ursatoro@candle:candle())) -> list(bigdecimal:big_decimal()).
compute_true_ranges(Candles) ->
case Candles of
[] ->
[];
[_] ->
[];
[First | Rest] ->
{Trs@1, _} = gleam@list:fold(
Rest,
{[], First},
fun(Acc, Current) ->
{Trs, Prev} = Acc,
Tr = ursatoro@util:true_range(Prev, Current),
{[Tr | Trs], Current}
end
),
lists:reverse(Trs@1)
end.
-file("src/ursatoro/volatility.gleam", 82).
-spec atr(list(ursatoro@candle:candle()), integer()) -> {ok, list(float())} |
{error, ursatoro@util:indicator_error()}.
atr(Candles, Period) ->
gleam@result:'try'(
ursatoro@util:validate_period(Period),
fun(_) ->
gleam@result:'try'(
ursatoro@util:validate_length(Candles, Period + 1),
fun(_) ->
True_ranges = compute_true_ranges(Candles),
Initial_trs = gleam@list:take(True_ranges, Period),
gleam@result:'try'(
ursatoro@util:bd_mean(Initial_trs),
fun(First_atr) ->
Remaining_trs = gleam@list:drop(True_ranges, Period),
Period_bd = ursatoro@util:int_to_bd(Period),
Period_minus_one = ursatoro@util:int_to_bd(
Period - 1
),
{Results@1, _} = gleam@list:fold(
Remaining_trs,
{[First_atr], First_atr},
fun(Acc, Tr) ->
{Results, Prev_atr} = Acc,
New_atr = bigdecimal:divide(
bigdecimal:add(
bigdecimal:multiply(
Prev_atr,
Period_minus_one
),
Tr
),
Period_bd,
half_up
),
{[New_atr | Results], New_atr}
end
),
{ok,
begin
_pipe = lists:reverse(Results@1),
ursatoro@util:bds_to_floats(_pipe)
end}
end
)
end
)
end
).
-file("src/ursatoro/volatility.gleam", 195).
-spec realized_variance(list(float())) -> float().
realized_variance(Returns) ->
N = erlang:length(Returns),
case N > 0 of
false ->
+0.0;
true ->
N_f = erlang:float(N),
Mean = case N_f of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> gleam@list:fold(
Returns,
+0.0,
fun(Acc, R) -> Acc + R end
)
/ Gleam@denominator
end,
Sum_sq = gleam@list:fold(
Returns,
+0.0,
fun(Acc@1, R@1) ->
Diff = R@1 - Mean,
Acc@1 + (Diff * Diff)
end
),
case N_f of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@1 -> Sum_sq / Gleam@denominator@1
end
end.
-file("src/ursatoro/volatility.gleam", 164).
-spec compute_har_series(
list(float()),
integer(),
integer(),
integer(),
list(har_result())
) -> list(har_result()).
compute_har_series(Returns, Daily, Weekly, Monthly, Acc) ->
case erlang:length(Returns) >= Monthly of
false ->
lists:reverse(Acc);
true ->
D_vol = realized_variance(gleam@list:take(Returns, Daily)),
W_vol = realized_variance(gleam@list:take(Returns, Weekly)),
M_vol = realized_variance(gleam@list:take(Returns, Monthly)),
Predicted = ((0.4 * D_vol) + (0.3 * W_vol)) + (0.3 * M_vol),
Result = {har_result, Predicted, D_vol, W_vol, M_vol},
case gleam@list:rest(Returns) of
{ok, Rest} ->
compute_har_series(
Rest,
Daily,
Weekly,
Monthly,
[Result | Acc]
);
{error, _} ->
lists:reverse([Result | Acc])
end
end.
-file("src/ursatoro/volatility.gleam", 212).
-spec compute_log_returns_float(list(float())) -> list(float()).
compute_log_returns_float(Prices) ->
case Prices of
[] ->
[];
[_] ->
[];
[First | Rest] ->
{Returns, _} = gleam@list:fold(
Rest,
{[], First},
fun(Acc, P) ->
{Rs, Prev} = Acc,
Ret = case Prev > +0.0 of
true ->
math:log(case Prev of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> P / Gleam@denominator
end);
false ->
+0.0
end,
{[Ret | Rs], P}
end
),
lists:reverse(Returns)
end.
-file("src/ursatoro/volatility.gleam", 144).
-spec har_volatility(
list(ursatoro@candle:candle()),
integer(),
integer(),
integer()
) -> {ok, list(har_result())} | {error, ursatoro@util:indicator_error()}.
har_volatility(Candles, Daily, Weekly, Monthly) ->
gleam@result:'try'(
ursatoro@util:validate_period(Daily),
fun(_) ->
gleam@result:'try'(
ursatoro@util:validate_period(Weekly),
fun(_) ->
gleam@result:'try'(
ursatoro@util:validate_period(Monthly),
fun(_) ->
Min_len = Monthly + 1,
gleam@result:'try'(
ursatoro@util:validate_length(Candles, Min_len),
fun(_) ->
Closes = gleam@list:map(
Candles,
fun(C) ->
ursatoro@util:bd_to_float(
ursatoro@candle:close(C)
)
end
),
Log_returns = compute_log_returns_float(
Closes
),
{ok,
compute_har_series(
Log_returns,
Daily,
Weekly,
Monthly,
[]
)}
end
)
end
)
end
)
end
).