Which hours of day do Bitcoin make biggest gains and losses? Is there a best time of the day to trade it? In this article I attempt to answer this question using statistics. This is an educational article, and is not investment or trading advice. Backtest performance never guarantees real-time trading performance.
For the analyses I used historical hourly Bitcoin prices between January 1st 2012 and May 5th 2021. I did not include slippage, commissions or taxes. I provide the R code I used to do the analyses so you can replicate it if you wanted to. However, you will have to get the data yourself.
There are a few packages we will use so I suggest you install them and load them.
install.packages("tidyverse","data.table","plyr","kableExtra","effsize")
library(ggplot2)
library(data.table)
library(plyr)
library(tidyverse)
library(kableExtra)
library(effsize)
Is there a best time of day to trade?
First let’s get the data and calculate descriptive statistics including mean, standard deviation, minimum, and maximum values for price percent change.
# read the data in to a data frame
hrs <- read_csv("hours.csv")
# create empty data frame to store descriptive statistics
hours <- data.frame("Hour" = character(),"Mean"=numeric(),"SD" = numeric(),"Min" = numeric(), "Max" = numeric(), stringsAsFactors = F)
hrs_distinct <-distinct(hrs,Hour)
# calculate descriptives for each day
for (i in 1:nrow(hrs_distinct)){
hr <- hrs_distinct[i,"Hour"]$Hour
now <- hrs %>% filter (Hour == hr)
meand <- round(mean(now$Percent), digits = 2)
sdd <- round(sd(now$Percent), digits = 2)
mind <- round(min(now$Percent), digits = 2)
maxd <- round(max(now$Percent), digits = 2)
hours[as.numeric(hr)+1,] <- c(hr,meand,sdd,mind,maxd)
}
# convert the columns to numeric
hours[,c(2:5)] <- sapply(hours[,c(2:5)], as.numeric)
# the descriptives table
hours %>% kbl(row.names=F) %>% kable_paper()
Let’s look at the descriptive statistics. The mean percent price change seems to fluctuate around zero, this doesn’t look significant. Standard deviation is also between 1 and 1.5, that seems similar across hours too. But look at the minimum and maximum price change percentages. Anything more than 25% happened at night hours or early in the morning. Day time seems much more stable.

Let’s see if we can detect a difference in price percentage changes with respect to hours.
# ANOVA
res.aov <- aov(Percent ~ Hour, data = hrs)
summary(res.aov)
# Tukey's test
kk<-TukeyHSD(res.aov, "Hour", ordered = TRUE)
kk$Hour
result<-data.frame( kk$Hour)
result["p.adj"]
I have not shown the comparisons table but there is nothing with p < 0.05. So not even statistical significance is detected. No need to look for practical significance.
Now I wonder if daytime and nighttime has an effect. I will define daytime as hour between 07:00 to 19:00 and nighttime as 20:00 to 06:00.
daytime <- hrs %>% mutate(is_day=ifelse(Hour < 20 | Hour > 6,"Day","Night"))
res.aov <- aov(Percent ~ is_day, data = daytime)
summary(res.aov)
The output shows:
Df Sum Sq Mean Sq F value Pr(>F)
is_day 1 5 4.769 3.924 0.0476 *
Residuals 78324 95199 1.215
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Looks like there is a statistically significant difference between day and night. Let’s see how it is further.
TukeyHSD(res.aov)
The output:
diff lwr upr p adj
Night-Day -0.0208619 -0.04150426 -0.0002195331 0.0476128
But is this practically significant?
day <- daytime %>% filter(is_day == "Day")
night<- daytime %>% filter(is_day == "Night")
cohen.d(day$Percent,night$Percent)
The output says no, the difference is negligible in practice:
Cohen's d
d estimate: 0.01892282 (negligible)
95 percent confidence interval:
lower upper
0.0001986041 0.0376470376
Finally let’s visualize the two distributions:
# clean to show the differences in means
daytime <- daytime %>% filter(Percent > -5 & Percent < 5)
# create the plot for weekends and weekdays
mu <- ddply(daytime, "is_day", summarise, grp.mean=mean(Percent))
ggplot(daytime, aes(x=Percent, color=is_day, fill=is_day)) +
geom_histogram(aes(y=..density..), position="identity", alpha=0.5, bins = 50)+
geom_density(alpha=0.6)+
geom_vline(data=mu, aes(xintercept=grp.mean, color=is_day),
linetype="dashed")+
scale_color_manual(values=c("#000000", "#ff0000", "#56B4E9"))+
scale_fill_manual(values=c("#cccccc", "#fff000", "#56B4E9"))+
labs(title="Day vs Night Price Change Percentage",x="Price Change %", y = "Density (Frequency)")+
theme_classic()

I was led to think that there might be a difference between day and night in terms of price percentage change, but I found no practically significant difference. What does this mean? We can interpret it as, the Bitcoin market does not sleep, any time of day is equally likely for a price change to happen. Let me say it again, this is not trading or investment advice.