Apply BuyTheDip to historical bitcoin prices & make plots
source("fns.R")
suppressMessages(library(dplyr))
suppressMessages(library(Hmisc))
suppressMessages(library(lubridate))
suppressMessages(library(data.table))
suppressMessages(library(tidyr))
suppressMessages(library(knitr))
if(file.exists("bitcoin_zscores.csv")){
dat <- fread("bitcoin_zscores.csv")
} else {
dat <- data.table::fread("historicalprices_bitcoin.csv")
dat <- do.call(rbind, pbmcapply::pbmclapply(1:nrow(dat), function(x) buythedip(x), mc.cores = 2))
dat <- dat[!duplicated(dat$datetime),]
write.csv(dat, "bitcoin_zscores.csv", row.names = F, quote = F)
}
cols = viridis::viridis(n=12)
- plot 1: historical bitcoin prices from 2018-10-02 to 2021-09-02
p1 <- dat %>%
select(coin_id, datetime, z.score, current.price) %>%
mutate(log_price = (current.price)) %>%
mutate(datetime = as.Date(datetime)) %>%
mutate(buy2 = ifelse(z.score < -2, (log_price)+(log_price*0.075), NA)) %>%
mutate(buy3 = ifelse(z.score < -3, (log_price)-(log_price*0.075), NA)) %>%
# reshape2::melt(., id.var=c("coin_id","datetime")) %>%
filter(!is.na(z.score)) %>%
ggplot(aes(x=datetime, y=log_price)) +
geom_line(size=0.25, col=cols[12], alpha=0.7, show.legend = F) +
# geom_point(aes(x=datetime, y=buy2), pch=25, col="white",alpha=0.05) +
# geom_point(aes(x=datetime, y=buy3), pch=24, col="red",alpha=0.05) +
scale_x_date(date_breaks = "3 months",limits = c(min(as.Date(dat$datetime)-5),NA),
date_minor_breaks = "1 month", date_labels = "%B\n%Y") +
ylab("bitcoin (USD)") +
theme(plot.background = element_rect(fill = 'grey15', colour = 'grey15'),
panel.background = element_rect(fill = 'grey15', colour = 'grey15'),
panel.grid.major = element_blank(),
# panel.grid.major.x = element_line(colour="white"),
axis.text.x = element_blank(),
axis.text.y = element_text(colour = "white"),
axis.title.y = element_text(colour = "white"),
axis.title.x = element_blank(),
panel.grid.minor = element_blank())
- plot 2: historical bitcoin z-scores from 2018-10-02 to 2021-09-02
p2 <- dat %>%
select(coin_id, datetime, z.score) %>%
mutate(datetime = as.Date(datetime)) %>%
# reshape2::melt(., id.var=c("coin_id","datetime")) %>%
filter(!is.na(z.score)) %>%
mutate(intercept1 = -2) %>%
mutate(intercept2 = -3) %>%
mutate(intercept3 = 2) %>%
mutate(intercept4 = 3) %>%
mutate(buy2 = ifelse(z.score < -2, min(z.score)-0.75, NA)) %>%
mutate(buy3 = ifelse(z.score < -3, min(z.score)-2.1, NA)) %>%
ggplot(aes(x=datetime, y=z.score)) +
geom_hline(yintercept=0, na.rm=TRUE, linetype="dotted", col="white") +
geom_hline(aes(yintercept=intercept1), na.rm=TRUE, linetype="dotted", col="red", alpha=0.5) +
geom_hline(aes(yintercept=intercept2), na.rm=TRUE, col="red", alpha=0.5) +
geom_hline(aes(yintercept=intercept3), na.rm=TRUE, linetype="dotted", col="green", alpha=0.5) +
geom_hline(aes(yintercept=intercept4), na.rm=TRUE, col="green", alpha=0.5) +
geom_line(size=0.25, col=cols[12], alpha=0.7, show.legend = F) +
geom_point(aes(x=datetime, y=buy2),na.rm=TRUE, pch=24, col="white",alpha=0.05) +
geom_point(aes(x=datetime, y=buy3),na.rm=TRUE, pch=24, col="red",alpha=0.05) +
annotate("text", x=min(as.Date(dat$datetime))-10, y=-9.2, hjust=1, vjust=0, col="white", cex=3, fontface = "bold", label = "buys @ -2") +
annotate("text", x=min(as.Date(dat$datetime))-10, y=-10.5, hjust=1, vjust=0, col="red", cex=3, fontface = "bold", label = "buys @ -3") +
scale_x_date(date_breaks = "3 months",limits = c(min(as.Date(dat$datetime)-50),NA), date_minor_breaks = "1 month", date_labels = "%B\n%Y", position = "top") +
ylab(" z-score") +
scale_y_continuous(breaks=seq(-3,3,1)) +
theme(plot.background = element_rect(fill = 'grey15', colour = 'grey15'),
panel.background = element_rect(fill = 'grey15', colour = 'grey15'),
panel.grid.major = element_blank(),
# panel.grid.major.x = element_line(colour="white"),
axis.text.x = element_text(colour = "white"),
axis.text.y = element_text(colour = "white"),
axis.title.y = element_text(colour = "white"),
axis.title.x = element_blank(),
panel.grid.minor = element_blank())
- plot 3: historical bitcoin prices in log scale from 2018-10-02 to 2021-09-02
p3 <- dat %>%
select(coin_id, datetime, z.score, current.price) %>%
mutate(log_price = log10(current.price)) %>%
mutate(datetime = as.Date(datetime)) %>%
mutate(buy2 = ifelse(z.score < -2, (log_price)+(log_price*0.075), NA)) %>%
mutate(buy3 = ifelse(z.score < -3, (log_price)-(log_price*0.075), NA)) %>%
# reshape2::melt(., id.var=c("coin_id","datetime")) %>%
filter(!is.na(z.score)) %>%
ggplot(aes(x=datetime, y=log_price)) +
geom_line(size=0.25, col=cols[12], alpha=0.7, show.legend = F) +
geom_point(aes(x=datetime, y=buy2), pch=25, na.rm=TRUE, col="white",alpha=0.05) +
geom_point(aes(x=datetime, y=buy3), pch=24, na.rm=TRUE, col="red",alpha=0.05) +
scale_x_date(date_breaks = "3 months",limits = c(min(as.Date(dat$datetime)-50),NA),
date_minor_breaks = "1 month", date_labels = "%B\n%Y", position = "top") +
annotate("text", x=min(as.Date(dat$datetime))-10, y=4.05, hjust=1, vjust=0, col="white", cex=3, fontface = "bold", label = "buys @ -2") +
annotate("text", x=min(as.Date(dat$datetime))-10, y=3.5, hjust=1, vjust=0, col="red", cex=3, fontface = "bold", label = "buys @ -3") +
ylab("log10(bitcoin)") +
theme(plot.background = element_rect(fill = 'grey15', colour = 'grey15'),
panel.background = element_rect(fill = 'grey15', colour = 'grey15'),
panel.grid.major = element_blank(),
# panel.grid.major.x = element_line(colour="white"),
axis.text.x = element_text(colour = "white"),
axis.text.y = element_text(colour = "white"),
axis.title.y = element_text(colour = "white"),
axis.title.x = element_blank(),
panel.grid.minor = element_blank())
Investment scenario
- total of \(7,700\) USD is invested in each scenario. For ease, I used \(60,000\) as today’s bitcoin price.
- S1: \(100.00\) dollars invested into bitcoin every two weeks between the period of 2018-10-02 to 2021-09-02. The span is around 154 weeks, so a total of 77 purchases were made, and we assume that the investor paid two-week average bitcoin price.
- S2: Bitcoin is bought everytime z-score dips below -2 (white arrows). This has happened 1000 times between 2018-10-02 to 2021-09-02 (which may sound like a lot, but keep in mind that the data is calculated hourly). To keep the comparisons fair, a total of \(7,700\) USD is invested (works out to be \(7.70\) USD per purchase).
- S3: Bitcoin is bought everytime z-score dips below -2 (red arrows). This has happened 139 times between 2018-10-02 to 2021-09-02, so now we’re talking real bit dips. Again, to keep the comparisons fair, a total of \(7,700\) USD is invested (works out to be \(55.39\) USD per purchase).
days = (max(dat$datetime) - min(dat$datetime))/14
dca_dates <- seq.Date(from=as.Date(min(dat$datetime)), to = as.Date(max(dat$datetime)), length.out=days)
dca <- dat %>%
arrange(datetime) %>%
mutate(dca = as.character(as.Date(datetime))) %>%
filter(dca %in% as.character(dca_dates)) %>%
group_by(coin_id, dca) %>%
summarise(mean_price = median(current.price, na.rm=TRUE), .groups = 'drop') %>%
mutate(fiat=100, bitcoins = fiat/mean_price) %>%
group_by(coin_id) %>%
summarise(n=n(),total_bitcoin = sum(bitcoins), total_fiat = sum(fiat), latest_price = 60000, .groups = 'drop') %>%
mutate(total_worth = total_bitcoin*latest_price, gain = total_worth-total_fiat, gain_per = gain/total_fiat*100) %>%
mutate(scenario = "S1: Scheduled purchase ($100 every two weeks)")
btd2 <- dat %>%
arrange(z.score) %>%
filter(z.score <= -2.0) %>%
mutate(fiat = dca$total_fiat/n(), bitcoins = fiat/current.price) %>%
group_by(coin_id) %>%
summarise(n=n(),total_bitcoin = sum(bitcoins), total_fiat = sum(fiat), latest_price = 60000) %>%
mutate(total_worth = total_bitcoin*latest_price, gain = total_worth-total_fiat, gain_per = gain/total_fiat*100) %>%
mutate(scenario = "S2: BuyTheDip @ z-score -2")
btd3 <- dat %>%
arrange(z.score) %>%
filter(z.score <= -3.0) %>%
mutate(fiat = dca$total_fiat/n(), bitcoins = fiat/current.price) %>%
group_by(coin_id) %>%
summarise(n=n(),total_bitcoin = sum(bitcoins), total_fiat = sum(fiat), latest_price = 60000) %>%
mutate(total_worth = total_bitcoin*latest_price, gain = total_worth-total_fiat, gain_per = gain/total_fiat*100) %>%
mutate(scenario = "S3: BuyTheDip @ z-score -3")
res <- rbind(dca,btd2,btd3) %>%
select(-coin_id) %>%
select(scenario, everything()) %>%
mutate(total_fiat = format.money(total_fiat),
latest_price = format.money(latest_price),
total_worth = format.money(total_worth),
gain = format.money((gain)),
gain_per = paste0(round(gain_per,1),"%"))
kable(res)
S1: Scheduled purchase ($100 every two weeks) |
77 |
0.8605088 |
$7,700.00 |
$60,000.00 |
$51,630.53 |
$43,930.53 |
570.5% |
S2: BuyTheDip @ z-score -2 |
1000 |
0.9195261 |
$7,700.00 |
$60,000.00 |
$55,171.56 |
$47,471.56 |
616.5% |
S3: BuyTheDip @ z-score -3 |
139 |
1.0259890 |
$7,700.00 |
$60,000.00 |
$61,559.34 |
$53,859.34 |
699.5% |