Skip to content

Commit

Permalink
Add bollinger bands (#16)
Browse files Browse the repository at this point in the history
* Plot Bollinger bands

* Add mode for Bollinger bands

* Add mode for Bollinger bands

* Fix Bollinger plot

* Add test for price std

* Remove extra lines + update docs

* Fix typo
  • Loading branch information
vnegi10 authored Jun 25, 2022
1 parent 4369296 commit cd7cc20
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 78 deletions.
22 changes: 15 additions & 7 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ The plots are interactive, which means you can hover your cursor over the data p

- Plot title also contains $R^2$, which is a statistical measure representing the proportion of variation in the dependent variable that is explained by different features (independent variables) in this model. A value closer to 1 (maximum) indicates a good fit. The linear regression channel metric will therefore not be very useful when $R^2 < 0.50$.

### Bollinger bands
- These are price envelopes plotted at two standard deviations (std) above (upper band) and below
(lower band) a simple moving average of the daily price. Since the distance towards the bands is
based on std, it adjusts in response to the price volatility.

- When the bands move closer (tighten during low volatility), it raises the chances of a sharp
price movement in either direction. On the contrary, diverging bands indicate high volatility,
which might also indicate the end for any existing trend.

- Prices often bounce between the two bands, which could be used to identify potential price
targets. For example, when a price bounces off of the lower band, and crosses the moving average,
the upper band might be considered as the next profit target. Prices can also cross the bands
during strong trends.

### Fundamental Cryptocurrency Asset Score (FCAS) data
- This metric tells us about the market health of an asset. In the case of cryptocurrencies, they are user activity, developer behavior, and market maturity, which are provided by [Flipside Crypto](https://app.flipsidecrypto.com/tracker/all-coins).

Expand All @@ -65,10 +79,4 @@ The plots are interactive, which means you can hover your cursor over the data p
## Run app
```@docs
run_app(port::Int64, key::String)
```






```
35 changes: 28 additions & 7 deletions src/ConfigureApp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ currencies_list = ["BTC", "LTC", "BCH", "ETH", "KNC", "LINK", "ETC", "BNB", "ADA
currencies = sort(currencies_list)
currencies_index = 1:length(currencies)

modes = ["Average price + Daily trade (AV)", "Candlestick + Volume (AV)",
"Cumulative + Daily return (AV)", "Daily volatility (AV)", "MACD + Signal (AV)",
"Linear regression channel (AV)", "FCAS data (AV)", "Developer + Community data (CG)",
"Exchange volume data per currency (CG)", "Overall exchange volume data (CG)"]
modes = ["Average price + Daily trade (AV)",
"Candlestick + Volume (AV)",
"Cumulative + Daily return (AV)",
"Daily volatility (AV)",
"MACD + Signal (AV)",
"Linear regression channel (AV)",
"Bollinger bands (AV)",
"FCAS data (AV)",
"Developer + Community data (CG)",
"Exchange volume data per currency (CG)",
"Overall exchange volume data (CG)"]

modes_index = 1:length(modes)

durations = [7, 14, 30, 90, 180, 270, 365, 500, 750, 1000]
Expand Down Expand Up @@ -282,6 +290,19 @@ function run_app(port::Int64, key::String)
return [P1]

elseif mode_ID == 7
t1, t2, t3, t4 = plot_price_bollinger_bands(pair_ID, duration_ID, window_ID)

layout1 = Layout(;title="Bollinger bands for $(currencies[pair_ID])",
xaxis = attr(title="Time", showgrid=true, zeroline=true),
yaxis = attr(title="Price [euros]", showgrid=true, zeroline=true),
height = 500,
width = 1000,
)

P1 = Plot([t1, t2, t3, t4], layout1) # plots Bollinger bands
return [P1]

elseif mode_ID == 8
t1, fr = plot_fcas_data(pair_ID)

layout1 = Layout(;title="FCAS metrics data for $(currencies[pair_ID]), overall rating = $(fr)",
Expand All @@ -295,7 +316,7 @@ function run_app(port::Int64, key::String)
return [P1]

# From CoinGecko
elseif mode_ID == 8
elseif mode_ID == 9
t1, t2 = plot_dev_comm_data(pair_ID)

layout1 = Layout(;title="Developer metrics for $(currencies[pair_ID])",
Expand All @@ -317,7 +338,7 @@ function run_app(port::Int64, key::String)
P2 = Plot(t2, layout2) # plots community data
return [P1 P2]

elseif mode_ID == 9
elseif mode_ID == 10

t1, t2 = plot_exchange_vol_data(pair_ID)

Expand All @@ -340,7 +361,7 @@ function run_app(port::Int64, key::String)
P2 = Plot(t2, layout2) # plots USD volume data for a given currency
return [P1 P2]

elseif mode_ID == 10
elseif mode_ID == 11

t_all = plot_overall_vol_data(duration_ID)

Expand Down
2 changes: 1 addition & 1 deletion src/CryptoDashApp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ include("GetDataFunctions.jl")
include("PlotFunctions.jl")
include("ConfigureApp.jl")

end # module
end # module
19 changes: 17 additions & 2 deletions src/CryptoFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ function moving_averages(Price_df::DataFrame, duration::Int64, window::Int64)
return Price_SMA, Price_WMA, Price_EMA
end

function moving_std(Price_df::DataFrame, duration::Int64, window::Int64)

# Price_df should have date order - oldest to latest
Price_col = Price_df[end-duration+1-window+1:end,2]
rows1 = length(Price_col)

Price_std = Float64[]

for i = 1:rows1-(window-1)
# Standard deviation over the period SMA is also being calculated
push!(Price_std, std(Price_col[i:i+(window-1)]))
end

return Price_std
end

function calculate_ema(Price_col::Vector{Float64}, window::Int64)

k(window) = 2/(window+1)
Expand Down Expand Up @@ -117,5 +133,4 @@ function calculate_macd(Price_df::DataFrame, window_long::Int64 = 26,
MACD = MACD_col[window_signal:end], Signal = Signal_col)

return df_ema
end

end
23 changes: 1 addition & 22 deletions src/GetDataFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -422,25 +422,4 @@ function get_overall_vol_data(duration::Int64, num_exchanges::Int64)
return DataFrame()
end

end





















end
71 changes: 40 additions & 31 deletions src/PlotFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,45 @@ function plot_price_ma_trade_data(index::Int64, duration::Int64, window::Int64)
return trace1, trace2, trace3, trace4, trace5
end

function plot_price_bollinger_bands(index::Int64, duration::Int64, window::Int64)

Price_df, _ , _ = get_price_data_single(currencies[index])

if duration > size(Price_df)[1]-maximum(windows)
duration = size(Price_df)[1]-maximum(windows)
end

sort!(Price_df, :Date) # oldest date first, newest at the bottom
Price_SMA, _ , _ = moving_averages(Price_df, duration, window)
Price_σ = moving_std(Price_df, duration, window)

################# Raw price data #################

trace1 = PlotlyJS.scatter(;x = Price_df[!,:Date][end-length(Price_SMA)+1:end],
y = Price_df[!,2][end-length(Price_SMA)+1:end],
mode = "markers+lines",
name = "$(currencies[index]) price")

################# SMA and Bollinger bands #################

trace2 = PlotlyJS.scatter(;x = Price_df[!,:Date][end-length(Price_SMA)+1:end],
y = Price_SMA,
mode = "lines",
name = "$(names(Price_df)[2]) SMA over $(window) days")

trace3 = PlotlyJS.scatter(;x = Price_df[!,:Date][end-length(Price_SMA)+1:end],
y = Price_SMA .+ 2*Price_σ,
mode = "markers",
name = "Upper band (+2σ)")

trace4 = PlotlyJS.scatter(;x = Price_df[!,:Date][end-length(Price_SMA)+1:end],
y = Price_SMA .- 2*Price_σ,
mode = "markers",
name = "Lower band (-2σ)")

return trace1, trace2, trace3, trace4
end

function plot_candle_vol_data(index::Int64, duration::Int64)

# Retrieve data from various helper functions
Expand Down Expand Up @@ -293,34 +332,4 @@ function plot_overall_vol_data(duration::Int64, num_exchanges::Int64 = 10)
end

return all_traces
end






























end
13 changes: 5 additions & 8 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ end

################# Test cases for moving averages #################

@testset "Check if MA, MACD and signal are calculated" begin
@testset "Check if MA, MACD + signal, σ (for Bollinger bands) are calculated" begin

for currency in ["BTC", "DOT"]

Expand All @@ -56,8 +56,10 @@ end

df_out_price = df_out_price[end-duration+1-26-9+1:end, :]
df_ema_all = CryptoDashApp.calculate_macd(df_out_price)

@test ~isempty(df_ema_all)

Price_σ = CryptoDashApp.moving_std(df_out_price, duration, window)
@test ~isempty(Price_σ)

end

Expand Down Expand Up @@ -125,9 +127,4 @@ end
@test ~isempty(dev_score)
@test ~isempty(mark_score)
@test ~isempty(fcas_rating)
end=#





end=#

0 comments on commit cd7cc20

Please sign in to comment.