diff --git a/README.md b/README.md index 4a1441d..1986af2 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ It's currently a work in progress; updates will be pushed on a regular basis. - Indicator - MACD (Moving Average Convergence Divergence) - RSI (Relative Strength Index) + - Bollinger Bands ## Why? diff --git a/lib/talib/average.ex b/lib/talib/average.ex index fd32218..fa9c0ac 100644 --- a/lib/talib/average.ex +++ b/lib/talib/average.ex @@ -35,7 +35,11 @@ defmodule Talib.Average do """ @spec mean([number]) :: {:ok, number} | {:error, atom} def mean([]), do: {:error, :no_data} - def mean(data), do: {:ok, Enum.sum(data) / length(data)} + def mean(data) do + {:ok, Enum.filter(data, &(Kernel.!=(&1, nil))) + |> (fn(x) -> Enum.sum(x)/Enum.count(x) end).() + } + end @doc """ Gets the median of a list. @@ -192,7 +196,10 @@ defmodule Talib.Average do """ @spec mean!([number]) :: number | no_return def mean!([]), do: raise NoDataError - def mean!(data), do: Enum.sum(data) / length(data) + def mean!(data) do + Enum.filter(data, &(Kernel.!=(&1, nil))) + |> (fn(x) -> Enum.sum(x)/Enum.count(x) end).() + end @doc """ Gets the median of a list. @@ -319,6 +326,36 @@ defmodule Talib.Average do |> map_max end + @doc false + @spec deviation!([number]) :: [number, ...] | number | no_return + def deviation!([]), do: raise NoDataError + def deviation!(data) do + m = data + |> mean! + + deviation_reduce(data, m) + end + + defp deviation_reduce(data, m) do + data + |> Enum.filter(&Kernel.!=(&1, nil)) + |> Enum.map(&:math.pow(&1 - m, 2)) + |> (fn (x) -> Enum.sum(x)/Enum.count(x) end).() + |> :math.sqrt() + end + + @doc false + @spec deviation([number]) :: [number, ...] | number | {:error, atom} + def deviation([]), do: {:error, :no_data} + def deviation(data) do + case data |> mean do + {:ok, m} -> deviation_reduce(data, m) + {:error, reason} -> {:error, reason} + end + end + + + @doc false @spec map_max(map()) :: number | [number, ...] defp map_max(map) do diff --git a/lib/talib/bollinger_band.ex b/lib/talib/bollinger_band.ex new file mode 100644 index 0000000..4f50393 --- /dev/null +++ b/lib/talib/bollinger_band.ex @@ -0,0 +1,159 @@ +defmodule Talib.BollingerBand do + alias Talib.SMA + alias Talib.Average + require OK + require Logger + + @moduledoc ~S""" + Defines a Bollinger bands. + + ## History + + Version: 1.0 + https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:bollinger_bands + Audited by: + + | Name | Title | + | :----------- | :---------------- | + | | | + + """ + + @typedoc """ + Defines a Bollinger Band price volatility. + * :period - Period used to calculate SMA, typically 20 + * :deviation - Multiplier to standard deviation from SMA typically 2 + * :values - List of values resulting from the calculation {upper, middle, lower} + """ + @type t :: %Talib.BollingerBand{ + period: integer, + deviation: integer, + values: [number] + } + + defstruct [ + period: 0, + deviation: 0, + values: [], + ] + + @doc """ + Gets the BBand of a list. + + The return tuple looks like the following: {MACD, MACD Signal}. + Raises `NoDataError` if the given list is an empty list. + + ## Examples + + iex>Talib.BollingerBand.from_list([1, 2, 3, 4, 5, 6], 3, 2) + {:ok, %Talib.BollingerBand{ + period: 3, + deviation: 2, + values: [ + {nil, nil, nil}, + {nil, nil, nil}, + {3.0, 2.0, 1.0}, + {4.6329931618554525, 3.0, 1.367006838144548}, + {5.6329931618554525, 4.0, 2.367006838144548}, + {6.6329931618554525, 5.0, 3.367006838144548} + ] + }} + + iex>Talib.BollingerBand.from_list([], 3, 2) + {:error, :no_data} + """ + @spec from_list([number], integer, integer) :: {:ok, Talib.BollingerBand.t} + | {:error, atom} + def from_list(data, period \\ 20, deviation \\ 2), + do: calculate(data, period, deviation) + + @doc """ + Gets the BBand of a list. + + The return tuple looks like the following: {Upper Band, Middle, Lower Band}. + Raises `NoDataError` if the given list is an empty list. + + ## Examples + + iex>Talib.BollingerBand.from_list!([1, 2, 3], 3, 2) + %Talib.BollingerBand{ + deviation: 2, + period: 3, + values: [ + {nil, nil, nil}, + {nil, nil, nil}, + {3.0, 2.0, 1.0} + ] + } + + iex>Talib.BollingerBand.from_list!([], 20, 2) + ** (NoDataError) no data error + """ + @spec from_list!([number], integer, integer) :: Talib.BBand.t + | no_return + def from_list!(data, period \\ 20, deviation \\ 2) do + case calculate(data, period, deviation) do + {:ok, result} -> result + {:error, :no_data} -> raise NoDataError + end + end + + defp calculate_bband_point(mid, stddev, deviation) when is_nil(mid) do + {nil, nil, nil} + end + + defp calculate_bband_point(mid, stddev, deviation) when is_nil(stddev) do + {nil, nil, nil} + end + + defp calculate_bband_point(mid, stddev, deviation) when is_float(stddev) and is_float(mid) do + band = (stddev * deviation) + {mid + band, mid, mid - band} + end + + defp calculate_bband_point(mid, stddev_series, deviation) when is_list(stddev_series) do + stddev = Average.deviation!(stddev_series) + calculate_bband_point(mid, stddev, deviation) + end + + @doc false + @spec calculate([number], integer, integer) :: {:ok, Talib.BollingerBand.t} + | {:error, atom} + defp calculate(data, period, deviation) do + OK.with do + %SMA{values: middle_band} <- SMA.from_list(data, period) + + + + bband_ = data + |> Enum.reverse + |> Enum.chunk_every(period, 1, [nil]) + |> Enum.reverse + |> Enum.map(&Enum.reverse(&1)) + + deficit = length(data) - length(bband_) + empty = Stream.cycle([nil]) + |> Enum.take(period) + + bband = Stream.cycle([empty]) + |> Enum.take(deficit) + |> Kernel.++(bband_) + |> Enum.zip(middle_band) + |> Enum.map(fn({series, m}) -> calculate_bband_point(m, series, deviation) end) + + #bband = Enum.chunk_every(shaped_data, period, 1, [7]) + #IO.inspect bband, limit: :infinity + #IO.inspect length(bband) + #|> Enum.zip(middle_band) + #|> Enum.map(fn({series, m}) -> calculate_bband_point(m, series, deviation) end) + + {:ok, %Talib.BollingerBand{ + period: period, + deviation: deviation, + values: bband, + }} + else + :no_data -> {:error, :no_data} + end + end +end diff --git a/lib/talib/indicator.ex b/lib/talib/indicator.ex index 241eb56..2e505b2 100644 --- a/lib/talib/indicator.ex +++ b/lib/talib/indicator.ex @@ -2,6 +2,7 @@ defmodule Talib.Indicator do alias Talib.MovingAverage alias Talib.Utility + alias Talib.SMA @moduledoc ~S""" Module containing indicator functions, such as the RSI. @@ -88,4 +89,5 @@ defmodule Talib.Indicator do 100 - 100 / (relative_strength + 1) end end + end diff --git a/lib/talib/sma.ex b/lib/talib/sma.ex index aad745a..e012b6f 100644 --- a/lib/talib/sma.ex +++ b/lib/talib/sma.ex @@ -98,8 +98,8 @@ defmodule Talib.SMA do length(data) >= period -> result = data |> Enum.take(period) - |> Enum.sum - |> Kernel./(period) + |> Enum.filter(&(Kernel.!=(&1, nil))) + |> (fn(x) -> Enum.sum(x)/Enum.count(x) end).() calculate(tl, period, results ++ [result]) end diff --git a/mix.exs b/mix.exs index 2cb2eb8..6818841 100644 --- a/mix.exs +++ b/mix.exs @@ -39,6 +39,7 @@ defmodule Talib.Mixfile do # # Type "mix help deps" for more examples and options defp deps do - [{:ok, "~> 1.6"}] + [{:ok, "~> 1.6"}, + ] end end diff --git a/mix.lock b/mix.lock deleted file mode 100644 index d10597c..0000000 --- a/mix.lock +++ /dev/null @@ -1 +0,0 @@ -%{"ok": {:hex, :ok, "1.6.2", "56dd875c79f6760f3ec8c5a7a2c94f27de1d31a1d4c66fc162557f056726d02b", [:mix], []}} diff --git a/test/average_test.exs b/test/average_test.exs index 5c79442..0c1b394 100644 --- a/test/average_test.exs +++ b/test/average_test.exs @@ -16,6 +16,7 @@ defmodule Talib.AverageTest do def numbers_median, do: (53 + 46) / 2 def numbers_mode, do: [30, 53, 89] def numbers_midrange, do: (6 + 100) / 2 + def numbers_deviation, do: 23.902458032595728 end test "mean/1" do @@ -67,4 +68,11 @@ defmodule Talib.AverageTest do assert Average.mode!([3]) == 3 assert_raise NoDataError, fn -> Average.mode!([]) end end + + test "deviation!/1" do + assert Average.deviation!(Fixtures.numbers) == Fixtures.numbers_deviation + assert Average.deviation!([3]) == 0.0 + assert_raise NoDataError, fn -> Average.deviation!([]) end + end + end diff --git a/test/bollinger_band_test.exs b/test/bollinger_band_test.exs new file mode 100644 index 0000000..28fccb6 --- /dev/null +++ b/test/bollinger_band_test.exs @@ -0,0 +1,447 @@ +defmodule Talib.BollingerBandTest do + use ExUnit.Case + alias Talib.BollingerBand + + doctest Talib.BollingerBand + + defmodule Fixtures do + def numbers do + [ + 89, 77, 53, 64, 78, 67, 30, 6, 24, 53, + 46, 30, 100, 48, 34, 69, 40, 44, 66, 89 + ] + end + + def numbers_with_nil do + [ + 89, 77, 53, 64, 78, 67, 30, 6, 24, 53, + 46, 30, 100, 48, 34, 69, nil, 40, 44, 66, + ] + end + + def numbers_9984 do + [ + 8808.0,8992.0,8775.0,8789.0, + 8806.0,8999.0,8922.0,8873.0, + 8775.0,8896.0,9050.0,9113.0, + 8895.0,8797.0,8485.0,8388.0, + 8464.0,8384.0,8488.0,8598.0, + 8636.0,8697.0,8660.0,8636.0, + 8602.0,8626.0,8554.0,8554.0, + 8503.0,8097.0,8080.0,8253.0, + 7922.0,7806.0,7950.0,7863.0, + 7752.0,7618.0,7600.0,7636.0, + 7598.0,7714.0,7980.0,7988.0, + 8028.0,7997.0,7970.0,8201.0, + 8217.0,8277.0,8180.0,8208.0, + 8218.0,8168.0,8501.0,8501.0, + 8557.0,8490.0,8490.0,8490.0, + 8461.0,8489.0,8555.0,8355.0, + 8525.0,8628.0,8579.0,8395.0, + 8415.0,8411.0,8412.0,8449.0, + 8287.0,8056.0,7889.0,7889.0, + 7697.0,7747.0,7765.0,7762.0, + 7862.0,8032.0,8197.0,8248.0, + 8011.0,8143.0,8157.0,8383.0, + 8340.0,8324.0,8288.0,8070.0, + 8259.0,8641.0,8397.0,8198.0, + 7997.0,7940.0,7842.0,7973.0, + 8000.0,8123.0,8151.0,8189.0, + 8293.0,8578.0,8758.0,8812.0, + 9376.0,9722.0,9722.0,9604.0, + 9650.0,9758.0,9857.0,9571.0, + 9598.0,9570.0,9254.0,9385.0, + 9276.0,9260.0,9367.0,9235.0, + 9232.0,9433.0,10050.0,10530.0, + 10490.0,10120.0,10070.0,10445.0, + 10170.0,9985.0,10020.0,9984.0, + 9821.0,9950.0,9854.0,10100.0, + 10175.0,10235.0,10100.0,10195.0, + 10300.0,10250.0,10245.0,9850.0, + 10005.0,9940.0,9906.0,10150.0, + 10495.0,10990.0,10945.0,10945.0, + 10710.0,10915.0,10880.0,11045.0, + 11045.0,10925.0,11065.0,10960.0, + 11470.0,11435.0,11190.0,11055.0, + 11200.0,11075.0,11075.0,10700.0, + 10125.0,9535.0,9976.0,9251.0, + 9586.0,9790.0,9648.0,9530.0, + 9433.0,9157.0,9205.0,8800.0, + 8628.0,8506.0,8539.0,9048.0, + 8310.0,8699.0,8747.0,8575.0, + 8557.0,8805.0,8785.0,8777.0, + 8941.0,9362.0,9109.0,8802.0, + 9250.0,8803.0,8865.0,8787.0, + 8787.0,8819.0,9145.0,9235.0, + 9518.0,9526.0,9653.0,9505.0, + 9593.0,9120.0,8929.0,8616.0, + 8827.0,9026.0,8909.0,8496.0, + 8540.0,8259.0,8184.0,7798.0, + 7621.0,7621.0,7043.0,6947.0, + 7280.0,7305.0,7305.0,7305.0, + 7305.0,7305.0,7094.0,7354.0, + 7772.0,7884.0,7589.0,7698.0, + 7698.0,7709.0,7699.0,7770.0, + 7834.0,7868.0,7839.0,8028.0, + 8025.0,8172.0,8076.0,8200.0, + 8138.0,8526.0,8450.0,8452.0, + 8416.0,8462.0,9962.0,10015.0, + 10015.0] + end + + def numbers_bband_5_2 do + [{nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {99.26935536727834, 72.2, 45.130644632721676}, + {92.6965861113527, 67.8, 42.9034138886473}, + {76.79130229211624, 58.4, 40.008697707883755}, + {81.56009827994995, 49.0, 16.439901720050045}, + {94.66563145999496, 41.0, -12.665631459994955}, + {90.25863986500215, 36.0, -18.258639865002145}, + {74.97406628984581, 31.8, -11.374066289845803}, + {65.03612492454559, 31.8, -1.4361249245455845}, + {83.83612492454557, 50.6, 17.363875075454423}, + {109.05966828074881, 55.4, 1.7403317192511878}, + {98.78643872978762, 51.6, 4.413561270212391}, + {106.50467175123997, 56.2, 5.895328248760038}, + {109.80465095318445, 58.2, 6.5953490468155636}, + {95.03998334720777, 47.0, -1.039983347207773}, + {74.46629422428208, 50.6, 26.733705775717926}, + {89.98591199873627, 61.6, 33.214088001263725} + ] + end + + def numbers_bband_5_2_9984 do + [ + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {9199.643410713641, 8764.85, 8330.05658928636}, + {9194.082787716954, 8756.25, 8318.417212283046}, + {9166.25145673676, 8741.5, 8316.74854326324}, + {9161.643824796744, 8735.75, 8309.856175203256}, + {9155.387210199417, 8728.1, 8300.812789800584}, + {9146.997611272773, 8717.9, 8288.802388727227}, + {9109.882621694867, 8699.25, 8288.617378305133}, + {9082.796401899557, 8680.85, 8278.903598100444}, + {9060.34552090016, 8664.9, 8269.454479099839}, + {9049.36436665444, 8651.3, 8253.23563334556}, + {9060.287980126432, 8611.35, 8162.412019873569}, + {9021.238601516225, 8562.85, 8104.461398483776}, + {8921.58686661794, 8519.85, 8118.113133382061}, + {8913.085324490416, 8471.2, 8029.314675509585}, + {8924.353600544098, 8421.65, 7918.946399455902}, + {8936.690328448192, 8394.9, 7853.109671551807}, + {8958.017890201018, 8368.65, 7779.282109798981}, + {8978.432204588877, 8333.05, 7687.667795411122}, + {9010.564745587153, 8294.75, 7578.935254412847}, + {9020.78605185635, 8250.35, 7479.9139481436505}, + {8999.514291185802, 8202.25, 7404.985708814198}, + {8962.908742491889, 8150.35, 7337.791257508112}, + {8894.234576799776, 8101.2, 7308.165423200224}, + {8818.709307992922, 8067.2, 7315.690692007078}, + {8739.863855264188, 8034.8, 7329.736144735812}, + {8661.452088575294, 8006.1, 7350.747911424706}, + {8565.150897543772, 7974.65, 7384.149102456228}, + {8472.854768654968, 7945.45, 7418.045231345032}, + {8392.45496876715, 7927.8, 7463.145031232852}, + {8320.492137516194, 7913.5, 7506.507862483807}, + {8352.628585425335, 7922.5, 7492.371414574664}, + {8367.057277268845, 7927.5, 7487.942722731155}, + {8358.535529414496, 7925.25, 7491.964470585504}, + {8391.712030726516, 7940.05, 7488.3879692734845}, + {8415.846963066175, 7958.15, 7500.4530369338245}, + {8500.845066947166, 7985.7, 7470.554933052834}, + {8575.632042090774, 8017.6, 7459.567957909226}, + {8648.613328245754, 8057.85, 7467.086671754247}, + {8684.591998144533, 8101.45, 7518.308001855466}, + {8704.553070167001, 8145.95, 7587.346929832998}, + {8714.395670452928, 8188.65, 7662.90432954707}, + {8694.425377600493, 8231.8, 7769.174622399505}, + {8679.967867221252, 8270.55, 7861.1321327787455}, + {8703.793807121938, 8299.3, 7894.806192878061}, + {8696.473586910846, 8317.65, 7938.826413089153}, + {8706.9949931069, 8342.5, 7978.005006893099}, + {8722.335787823735, 8374.05, 8025.764212176264}, + {8710.022175954546, 8404.5, 8098.977824045455}, + {8705.237866952051, 8414.2, 8123.162133047949}, + {8700.746995284604, 8424.1, 8147.453004715396}, + {8699.241129486521, 8430.8, 8162.358870513477}, + {8685.325832302782, 8442.4, 8199.474167697217}, + {8672.2852359009, 8454.45, 8236.614764099102}, + {8662.425695207228, 8457.9, 8253.374304792771}, + {8691.468643429693, 8452.3, 8213.131356570306}, + {8762.937805642927, 8421.7, 8080.462194357074}, + {8801.214569358368, 8391.1, 7980.985430641632}, + {8849.745651830055, 8348.1, 7846.454348169947}, + {8871.632610752287, 8310.95, 7750.267389247714}, + {8876.621290535566, 8274.7, 7672.778709464435}, + {8871.001224907934, 8238.3, 7605.598775092065}, + {8852.651257177107, 8208.35, 7564.0487428228935}, + {8820.718545069332, 8185.5, 7550.281454930668}, + {8779.924554464378, 8167.6, 7555.275445535622}, + {8769.782674018443, 8162.25, 7554.717325981557}, + {8723.671614318533, 8136.55, 7549.428385681467}, + {8654.575981396927, 8112.3, 7570.024018603073}, + {8590.31946465751, 8091.2, 7592.080535342489}, + {8588.283996126056, 8090.6, 7592.916003873945}, + {8575.75296583269, 8086.85, 7597.94703416731}, + {8561.231448726736, 8082.5, 7603.768551273263}, + {8540.801926799018, 8076.3, 7611.798073200983}, + {8489.267249018838, 8057.35, 7625.432750981164}, + {8485.053006281709, 8055.95, 7626.846993718291}, + {8584.36313966478, 8085.2, 7586.036860335221}, + {8618.8599334986, 8110.6, 7602.340066501401}, + {8625.12894165152, 8126.05, 7626.971058348481}, + {8604.400612387639, 8141.05, 7677.6993876123615}, + {8588.136212492747, 8150.7, 7713.263787507252}, + {8579.517516405665, 8154.55, 7729.582483594334}, + {8559.973600029174, 8165.1, 7770.226399970827}, + {8549.90527913751, 8172.0, 7794.094720862489}, + {8549.76547395573, 8176.55, 7803.33452604427}, + {8547.499983255191, 8174.25, 7801.00001674481}, + {8543.101613767343, 8171.3, 7799.498386232658}, + {8553.182761966898, 8185.4, 7817.617238033102}, + {8611.920688168004, 8207.15, 7802.379311831995}, + {8706.679967623753, 8237.2, 7767.720032376248}, + {8788.176684879996, 8258.65, 7729.123315120002}, + {9030.197309824774, 8310.45, 7590.702690175226}, + {9327.424500765384, 8380.35, 7433.275499234617}, + {9563.214159789182, 8452.05, 7340.885840210817}, + {9731.812571107588, 8528.75, 7325.687428892412}, + {9888.609280754035, 8598.3, 7307.990719245962}, + {10040.164902517285, 8654.15, 7268.135097482715}, + {10202.231594353343, 8727.15, 7252.068405646656}, + {10293.6087461355, 8795.8, 7297.9912538644985}, + {10365.443135725323, 8875.85, 7386.256864274677}, + {10411.146584808204, 8957.35, 7503.5534151917955}, + {10392.642709000822, 9027.95, 7663.2572909991795}, + {10381.26656651031, 9098.55, 7815.833433489689}, + {10343.034254997923, 9162.35, 7981.6657450020775}, + {10299.45230386239, 9219.2, 8138.947696137611}, + {10243.492189900884, 9280.0, 8316.507810099116}, + {10156.754267985798, 9332.3, 8507.8457320142}, + {10055.186942325245, 9379.25, 8703.313057674755}, + {9989.237163803642, 9422.0, 8854.762836196358}, + {10030.440932626443, 9486.6, 8942.759067373558}, + {10199.37111913056, 9572.5, 8945.62888086944}, + {10363.860410787478, 9628.2, 8892.539589212523}, + {10413.75394271825, 9648.1, 8882.446057281752}, + {10452.597579719313, 9665.5, 8878.402420280687}, + {10563.831139579752, 9707.55, 8851.268860420247}, + {10612.539755344167, 9733.55, 8854.560244655831}, + {10630.695439139308, 9744.9, 8859.104560860691}, + {10645.793294570169, 9753.05, 8860.30670542983}, + {10667.749238017685, 9773.7, 8879.650761982317}, + {10675.411682310665, 9784.85, 8894.288317689336}, + {10691.475433389558, 9803.85, 8916.224566610443}, + {10684.91692451299, 9833.85, 8982.78307548701}, + {10702.112198108833, 9869.6, 9037.087801891168}, + {10710.273689480211, 9914.55, 9118.826310519788}, + {10710.642250913193, 9963.3, 9215.957749086805}, + {10696.922158697893, 9999.95, 9302.977841302109}, + {10653.865332369136, 10047.95, 9442.034667630865}, + {10586.404749487107, 10101.35, 9616.295250512894}, + {10521.2570405625, 10142.2, 9763.142959437502}, + {10531.050764968893, 10151.95, 9772.849235031108}, + {10476.758848831798, 10117.95, 9759.141151168204}, + {10411.911941950644, 10093.7, 9775.488058049357}, + {10409.540330008453, 10084.7, 9759.859669991549}, + {10410.559575525085, 10076.5, 9742.440424474915}, + {10352.692520096323, 10061.75, 9770.807479903677}, + {10422.657511161442, 10078.0, 9733.342488838558}, + {10651.038245851032, 10128.25, 9605.461754148968}, + {10803.645293235195, 10174.5, 9545.354706764805}, + {10928.286912737316, 10222.55, 9516.813087262683}, + {10977.939097250954, 10267.0, 9556.060902749046}, + {11063.584918335368, 10315.25, 9566.915081664632}, + {11122.007867786151, 10366.55, 9611.092132213847}, + {11213.57211754349, 10413.8, 9614.027882456508}, + {11294.165604502898, 10457.3, 9620.434395497101}, + {11345.877420378269, 10491.8, 9637.72257962173}, + {11409.041478669382, 10540.05, 9671.058521330617}, + {11450.511923789167, 10578.3, 9706.088076210832}, + {11580.516186149203, 10636.8, 9693.083813850795}, + {11682.994674234578, 10696.05, 9709.10532576542}, + {11729.828073599529, 10743.3, 9756.77192640047}, + {11708.288520236647, 10803.55, 9898.811479763352}, + {11704.828157580007, 10863.3, 10021.771842419992}, + {11650.63482738146, 10920.05, 10189.465172618538}, + {11543.505309709564, 10978.5, 10413.494690290436}, + {11446.948976640155, 11006.0, 10565.051023359845}, + {11531.62774235468, 10987.5, 10443.37225764532}, + {11749.528263971937, 10914.75, 10079.971736028063}, + {11795.56446181913, 10866.3, 9937.035538180868}, + {11945.832004370262, 10781.6, 9617.367995629738}, + {12001.201301143716, 10725.4, 9449.598698856284}, + {12004.371970310554, 10669.15, 9333.928029689445}, + {12010.153789386011, 10607.55, 9204.946210613987}, + {11994.091161157721, 10531.8, 9069.508838842277}, + {11968.140157026639, 10451.2, 8934.259842973363}, + {11962.782074899591, 10362.8, 8762.817925100408}, + {11911.393689071689, 10269.8, 8628.20631092831}, + {11889.503979274226, 10161.8, 8434.096020725772}, + {11761.085207241638, 10019.7, 8278.314792758363}, + {11606.534382321608, 9873.25, 8139.965617678392}, + {11456.297633479368, 9740.7, 8025.102366520635}, + {11269.30196675654, 9640.35, 8011.39803324346}, + {11057.076476203885, 9495.85, 7934.6235237961155}, + {10794.521477667187, 9377.05, 7959.578522332811}, + {10468.050227762113, 9260.65, 8053.249772237888}, + {10199.549061139127, 9154.4, 8109.250938860872}, + {10051.046050194554, 9076.0, 8100.953949805446}, + {9997.59070551801, 9039.5, 8081.4092944819895}, + {9840.938147421322, 8979.95, 8118.961852578679}, + {9812.169359519341, 8956.25, 8100.330640480658}, + {9729.70912865624, 8924.0, 8118.290871343758}, + {9634.524149075572, 8902.6, 8170.675850924428}, + {9531.549161457004, 8875.65, 8219.750838542996}, + {9422.648620156064, 8839.25, 8255.851379843936}, + {9380.78535480799, 8830.1, 8279.414645192011}, + {9342.282402047851, 8812.4, 8282.517597952148}, + {9294.745331409036, 8795.4, 8296.054668590963}, + {9294.103532079227, 8794.75, 8295.396467920773}, + {9296.209918846624, 8802.7, 8309.190081153378}, + {9292.712003115765, 8818.35, 8343.987996884236}, + {9325.178813399567, 8848.65, 8372.121186600432}, + {9356.633332219177, 8858.0, 8359.366667780823}, + {9429.3811738215, 8918.4, 8407.418826178498}, + {9524.082127385993, 8959.75, 8395.417872614007}, + {9635.390376304738, 9005.05, 8374.70962369526}, + {9685.333393597528, 9051.55, 8417.76660640247}, + {9736.331919173052, 9103.35, 8470.36808082695}, + {9737.102233005675, 9119.1, 8501.097766994326}, + {9731.79355075013, 9126.3, 8520.806449249869}, + {9745.977926732594, 9118.25, 8490.522073267406}, + {9748.627188712187, 9112.55, 8476.472811287811}, + {9722.262849030249, 9095.75, 8469.237150969751}, + {9717.460653701519, 9085.75, 8454.039346298481}, + {9742.447165172593, 9070.45, 8398.452834827409}, + {9739.48317168179, 9034.95, 8330.416828318212}, + {9784.323982309477, 9007.75, 8231.176017690523}, + {9828.139488787825, 8973.7, 8119.2605112121755}, + {9919.121021791267, 8924.25, 7929.378978208733}, + {10011.418196852275, 8865.95, 7720.481803147727}, + {10073.837281053095, 8806.05, 7538.262718946904}, + {10171.253434669185, 8700.95, 7230.646565330817}, + {10219.850030612868, 8586.55, 6953.2499693871305}, + {10143.62492791234, 8474.65, 6805.67507208766}, + {10033.539448004029, 8363.6, 6693.660551995972}, + {9866.441660987644, 8246.2, 6625.958339012357}, + {9697.301867271959, 8136.2, 6575.09813272804}, + {9470.390708240255, 8021.8, 6573.2092917597465}, + {9319.223112403493, 7931.05, 6542.876887596507}, + {9193.664072175572, 7839.3, 6484.935927824427}, + {9097.118710595016, 7776.2, 6455.281289404984}, + {8953.435117796147, 7723.45, 6493.464882203853}, + {8746.002587641044, 7666.35, 6586.697412358957}, + {8517.185050595253, 7600.35, 6683.514949404747}, + {8382.452305349565, 7560.45, 6738.447694650435}, + {8211.515571851343, 7518.35, 6825.1844281486565}, + {8103.231017014735, 7490.85, 6878.468982985266}, + {8000.671306100599, 7466.6, 6932.528693899401}, + {7995.925390385649, 7465.2, 6934.474609614351}, + {8026.816160485379, 7475.85, 6924.883839514621}, + {8062.217630391262, 7488.2, 6914.182369608738}, + {8083.096027728537, 7528.0, 6972.903972271463}, + {8110.191827542565, 7582.05, 7053.908172457435}, + {8161.865793245391, 7619.3, 7076.73420675461}, + {8235.536821283227, 7662.65, 7089.763178716773}, + {8276.390264173517, 7701.2, 7126.009735826483}, + {8330.072410116236, 7745.95, 7161.827589883764}, + {8358.663359006687, 7787.6, 7216.536640993314}, + {8459.936602176098, 7848.65, 7237.363397823901}, + {8476.547304046358, 7916.45, 7356.35269595364}, + {8515.175072978434, 7971.35, 7427.524927021565}, + {8572.05065083516, 8003.55, 7435.04934916484}, + {8631.64027862608, 8032.45, 7433.259721373919}, + {9155.102370515131, 8151.1, 7147.097629484871}, + {9535.059060767253, 8266.95, 6998.840939232749}, + {9832.217345004536, 8382.8, 6933.382654995463} + ] + end + + + def numbers_bband_5_2_with_nil do + [{nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {nil, nil, nil}, + {99.26935536727834, 72.2, 45.130644632721676}, + {92.6965861113527, 67.8, 42.9034138886473}, + {76.79130229211624, 58.4, 40.008697707883755}, + {81.56009827994995, 49.0, 16.439901720050045}, + {94.66563145999496, 41.0, -12.665631459994955}, + {90.25863986500215, 36.0, -18.258639865002145}, + {74.97406628984581, 31.8, -11.374066289845803}, + {65.03612492454559, 31.8, -1.4361249245455845}, + {83.83612492454557, 50.6, 17.363875075454423}, + {109.05966828074881, 55.4, 1.7403317192511878}, + {98.78643872978762, 51.6, 4.413561270212391}, + {106.50467175123997, 56.2, 5.895328248760038}, + {114.35465095318443, 62.75, 11.14534904681556}, + {97.4566393955576, 47.75, -1.956639395557609}, + {73.22168298389809, 46.75, 20.278317016101905}, + {81.40989497353657, 54.75, 28.090105026463437}] + end + end + + test "from_list/4" do + assert BollingerBand.from_list(Fixtures.numbers, 5, 2) == + {:ok, %Talib.BollingerBand{ + period: 5, + deviation: 2, + values: Fixtures.numbers_bband_5_2 + }} + + assert BollingerBand.from_list(Fixtures.numbers_9984, 20, 2) == + {:ok, %Talib.BollingerBand{ + period: 20, + deviation: 2, + values: Fixtures.numbers_bband_5_2_9984 + }} + + + assert BollingerBand.from_list(Fixtures.numbers_with_nil, 5, 2) == + {:ok, %Talib.BollingerBand{ + period: 5, + deviation: 2, + values: Fixtures.numbers_bband_5_2_with_nil + }} + + + assert BollingerBand.from_list([3], 3, 2) == + {:ok, %Talib.BollingerBand{ + period: 3, + deviation: 2, + values: [{nil, nil, nil}] + }} + + assert BollingerBand.from_list([1]) == + {:ok, %Talib.BollingerBand{ + period: 20, + deviation: 2, + values: [{nil, nil, nil}] + }} + + assert BollingerBand.from_list([]) === {:error, :no_data} + end +end diff --git a/test/sma_test.exs b/test/sma_test.exs index eef653d..3f99a5e 100644 --- a/test/sma_test.exs +++ b/test/sma_test.exs @@ -12,6 +12,13 @@ defmodule Talib.SMATest do ] end + def numbers_with_nil do + [ + 89, 77, 53, 64, 78, 67, 30, 6, 24, 53, + 46, 30, 100, 48, 34, 69, 40, nil, 66, 89 + ] + end + def numbers_sma_10 do [ nil, nil, nil, nil, nil, @@ -20,6 +27,16 @@ defmodule Talib.SMATest do 44.0, 45.0, 48.8, 53.0, 56.6 ] end + + def numbers_sma_10_with_nil do + [ + nil, nil, nil, nil, nil, + nil, nil, nil, nil, 54.1, + 49.8, 45.1, 49.8, 48.2, 43.8, + 44.0, 45.0, 49.333333333333336, + 54.0, 58.0 + ] + end end test "from_list/2" do @@ -29,6 +46,12 @@ defmodule Talib.SMATest do values: Fixtures.numbers_sma_10 }} + assert SMA.from_list(Fixtures.numbers_with_nil, 10) == + {:ok, %Talib.SMA{ + period: 10, + values: Fixtures.numbers_sma_10_with_nil + }} + assert SMA.from_list([nil, 87, 77], 2) == {:ok, %Talib.SMA{ period: 2,