Skip to main content

Technical analysis without external libraries

· 4 min read
AI prompt: graph of a moving average, multiple wavy lines, isolated dark blue background
JJ Brosnan
Calculating indicators and oscillators

In my last blog, I discussed the use of Bollinger Bands in financial analysis, as well as showed an implementation in Deephaven that took only two table operations.

Deephaven makes implementing technical indicators easy without any third-party integrations.

Effective trading strategies typically require more than one technical indicator. Bollinger Bands are a great place to start, but how are others implemented in a tool like Deephaven? Many of the most popular and useful indicators are also easy to implement with Deephaven alone.

Data

All examples in this blog will use a cryptocurrency history dataset of trade data from September 22, 2021. The calculations will be done on a per-instrument-exchange pair basis.

Quick analysis shows that this data has 17 unique instrument/exchange pairs. There are 4 unique instruments and 7 different exchanges.

from deephaven import read_csv

crypto_table = read_csv("https://media.githubusercontent.com/media/deephaven/examples/main/CryptoCurrencyHistory/CSV/CryptoTrades_20210922.csv")
instrument_exchange_pairs = crypto_table.select_distinct(["Instrument", "Exchange"])

Indicators

Each of the following sections will briefly discuss an indicator and show how to implement it in Deephaven. Because each indicator's implementations share many similarities, things are kept simple.

Moving average convergence divergence (MACD)

MACD is calculated by subtracting a longer-term EMA from a shorter-term EMA. It's compared with a signal line, which is the MACD's moving average. This indicator is used to evaluate current market conditions.

A one-minute bar is used for this calculation. The shorter-period EMA uses 12 bars, the longer-period EMA uses 26 bars, and the signal line is calculated using 9 bars. The MACD calculation is enclosed in comments in the code. It only takes three table operations: two update_by statements and an update.

from deephaven.updateby import ema_time, rolling_avg_time
from deephaven.replay import TableReplayer
from deephaven.plot.figure import Figure
from deephaven.time import to_j_instant
from deephaven import read_csv

crypto_table = read_csv("https://media.githubusercontent.com/media/deephaven/examples/main/CryptoCurrencyHistory/CSV/CryptoTrades_20210922.csv")

ema_12min = ema_time(ts_col="Timestamp", decay_time="PT12m", cols=["EMA_12Min = Price"])
ema_26min = ema_time(ts_col="Timestamp", decay_time="PT26m", cols=["EMA_26Min = Price"])
sma_9min = rolling_avg_time(ts_col="Timestamp", cols=["Signal = MACD"], rev_time="PT9m")

# Calculating MACD
crypto_macd = crypto_table.update_by(
ops=[ema_12min, ema_26min],
by=["Instrument", "Exchange"]
).update(
formulas=["MACD = EMA_12Min - EMA_26Min"]
).update_by(
ops=[sma_9min],
by=["Instrument", "Exchange"]
)
# Done calculating MACD

btc_binance_macd = crypto_macd.where(["Instrument == `BTC/USD`", "Exchange == `binance`"])

btc_binance_macd_plot = Figure().\
plot_xy(series_name="MACD", t=btc_binance_macd, x="Timestamp", y="MACD").\
plot_xy(series_name="Signal", t=btc_binance_macd, x="Timestamp", y="Signal").\
chart_title(title="BTC on Binance MACD vs signal").\
show()

Stochastic oscillator

The Stochastic oscillator is a momentum indicator that's useful for identifying if an asset is overbought or oversold. The stochastic oscillator requires keeping track of the highest and lowest trade prices of an asset over 14 periods.

In the code below, a one-minute bar is used.

from deephaven.updateby import rolling_min_time, rolling_max_time
from deephaven.replay import TableReplayer
from deephaven.plot.figure import Figure
from deephaven.time import to_j_instant
from deephaven import read_csv

crypto_table = read_csv("https://media.githubusercontent.com/media/deephaven/examples/main/CryptoCurrencyHistory/CSV/CryptoTrades_20210922.csv")

min_14m = rolling_min_time(ts_col="Timestamp", cols=["Min_14m = Price"], rev_time="PT14m")
max_14m = rolling_max_time(ts_col="Timestamp", cols=["Max_14m = Price"], rev_time="PT14m")

# Calculating stochastic oscillator
crypto_so = crypto_table.update_by(
ops=[min_14m, max_14m],
by=["Instrument", "Exchange"]
).update(
formulas=["StochOsc = ((Price - Min_14m)/(Max_14m - Min_14m)) * 100"]
)
# Done calculating stochastic oscillator

btc_binance_so = crypto_so.where(["Instrument == `BTC/USD`", "Exchange == `binance`"])
eth_binance_so = crypto_so.where(["Instrument == `ETH/USD`", "Exchange == `binance`"])

binance_so_plot = Figure().\
plot_xy(series_name="BTC/Binance", t=btc_binance_so, x="Timestamp", y="StochOsc").\
plot_xy(series_name="ETH/Binance", t=eth_binance_so, x="Timestamp", y="StochOsc").\
chart_title(title="Stochastic Oscillator for BTC and ETH trades on Binance").\
show()

Absolute price oscillator (APO)

APO is yet another indicator that gives insight into bullish or bearish behavior of an asset. It requires keeping track of two EMAs: one for a shorter period, and one for a longer period. The longer is subtracted from the shorter. The example below uses a 5-minute and 15-minute EMA, respectively.

from deephaven.updateby import ema_time
from deephaven.replay import TableReplayer
from deephaven.plot.figure import Figure
from deephaven.time import to_j_instant
from deephaven import read_csv

crypto_table = read_csv("https://media.githubusercontent.com/media/deephaven/examples/main/CryptoCurrencyHistory/CSV/CryptoTrades_20210922.csv")

ema_5min = ema_time(ts_col="Timestamp", decay_time="PT5m", cols=["EMA_5Min = Price"])
ema_15min = ema_time(ts_col="Timestamp", decay_time="PT15m", cols=["EMA_15Min = Price"])

# Calculating absolute price oscillator
crypto_apo = crypto_table.update_by(
ops=[ema_5min, ema_15min],
by=["Instrument", "Exchange"]
).update(
formulas=["APO = EMA_5Min - EMA_15Min"]
)
# Done calculating APO

btc_binance_apo = crypto_apo.where(["Instrument == `BTC/USD`", "Exchange == `binance`"])

btc_binance_apo_plot = Figure().\
plot_xy(series_name="BTC/Binance Price", t=btc_binance_apo, x="Timestamp", y="Price").\
x_twin().\
plot_xy(series_name="BTC/Binance APO", t=btc_binance_apo, x="Timestamp", y="APO").\
chart_title(title="Price and APO for BTC trades on Binance").\
show()

Reach out

Our Community documentation has all of the resources you need to become a Deephaven power user. Our Slack community continues to grow, and we'd love to have you join us! If you have any questions, comments, or suggestions, please reach out to us there.