Code
1 + 1[1] 2
Consulting Report
Quarto enables you to weave together content and executable code into a finished document. To learn more about Quarto see https://quarto.org.
When you click the Render button a document will be generated that includes both content and the output of embedded code. You can embed code like this:
1 + 1[1] 2
You can add options to executable code like this
[1] 4
The echo: false option disables the printing of code (only output is displayed).
library(tidyverse)
library(quantmod)
library(TTR)
library(xts)
library(zoo)
library(lubridate)
library(caret)
library(rpart)
library(randomForest)
library(xgboost)
library(kernlab)
library(nnet)
library(fastshap)
library(shapviz)This consulting report evaluates the forecasting framework developed for Bitcoin (BTC-USD).
The analysis follows the complete analytical chain:
Data → Features → ML Models → Evaluation → Diebold-Mariano Test → Forecast Decision Engine → SHAP → Investment Recommendation
The final executive findings will be completed after model evaluation, statistical validation, explainable artificial intelligence analysis, and executive recommendation outputs are generated.
The Investment Committee requires a forecasting framework that can support investment decision-making through a structured analytical process.
The purpose of this project is to develop a financial forecasting and investment analytics framework that evaluates whether machine-learning models can provide useful predictive information for Bitcoin (BTC-USD).
The analysis follows the complete analytical chain:
Data → Features → ML Models → Evaluation → Diebold-Mariano Test → Forecast Decision Engine → SHAP → Investment Recommendation
The framework focuses not only on predictive performance but also on statistical validation and model explainability.
The forecasting process evaluates multiple machine-learning approaches, compares their out-of-sample forecasting performance, determines whether differences between models are statistically meaningful, explains the selected model behavior, and translates the results into an executive-level investment recommendation.
The target asset selected for this analysis is:
Bitcoin (BTC-USD)
The forecasting framework focuses on Bitcoin market behavior and evaluates whether machine-learning models can provide predictive information regarding future Bitcoin returns.
The analysis incorporates Bitcoin market data together with assigned external financial predictors:
These external predictors are included to capture additional financial market information that may contribute to Bitcoin return forecasting.
The forecasting target is:
Bitcoin t+3 Log Return
The objective is to forecast the return occurring at t+3 using information available at the forecast origin date t.
The forecasting framework does not predict the Bitcoin price directly. Instead, it forecasts the future Bitcoin log return occurring three Bitcoin trading periods ahead.
The daily Bitcoin log return is calculated as:
[ btc_log_return = log ( ) ]
where:
The forecasting target is constructed by shifting the Bitcoin daily log-return series three periods forward.
The target is defined as:
[ target_{t+3}=log ( ) ]
This represents the return that occurs at the future period t+3.
The target is therefore not:
[ log ( ) ]
Instead, information available at time t is used to predict the Bitcoin return that will occur three Bitcoin trading periods into the future.
The model incorporates the following external predictors:
| Predictor | Description |
|---|---|
| Gold | Gold market information |
| VIX | CBOE Volatility Index representing market volatility |
| 10-Year U.S. Treasury Yield | U.S. Treasury market information |
The inclusion of these predictors allows the forecasting framework to consider both Bitcoin-specific information and broader financial market conditions.
# Load integrated modeling dataset
model_data <- read_csv(
"data_processed/model_data.csv",
show_col_types = FALSE
)
head(model_data)# A tibble: 6 × 15
date target_date_t3 btc_log_return btc_return_lag1 btc_return_lag2
<date> <date> <dbl> <dbl> <dbl>
1 2014-10-01 2014-10-04 -0.00864 0.0301 -0.00455
2 2014-10-02 2014-10-05 -0.0225 -0.00864 0.0301
3 2014-10-03 2014-10-06 -0.0424 -0.0225 -0.00864
4 2014-10-06 2014-10-09 0.0294 -0.0257 -0.0891
5 2014-10-07 2014-10-10 0.0183 0.0294 -0.0257
6 2014-10-08 2014-10-11 0.0486 0.0183 0.0294
# ℹ 10 more variables: btc_return_lag3 <dbl>, btc_sma7 <dbl>, btc_rsi14 <dbl>,
# btc_williams_r14 <dbl>, btc_obv <dbl>, btc_parkinson_vol7 <dbl>,
# gold_log_return <dbl>, vix_close <dbl>, treasury_10y <dbl>, target_t3 <dbl>
The financial datasets used in this analysis were collected to support the development of the Bitcoin (BTC-USD) forecasting framework.
The target asset and assigned external predictors are:
| Dataset | Identifier | Source | Purpose |
|---|---|---|---|
| Bitcoin | BTC-USD | Yahoo Finance | Target asset |
| Gold | GC=F | Yahoo Finance | External predictor |
| CBOE Volatility Index | ^VIX | Yahoo Finance | External predictor |
| 10-Year U.S. Treasury Yield | DGS10 | Financial market data source | External predictor |
The target asset selected for this analysis is Bitcoin (BTC-USD).
The assigned external predictors included in the forecasting framework are:
These predictors were selected to incorporate broader financial market information into the Bitcoin forecasting framework.
The data acquisition period was defined as:
The dataset was collected using daily financial observations.
The downloaded datasets were converted into structured data tables and prepared for integration, feature engineering, exploratory analysis, and machine-learning modeling.
The Bitcoin dataset was downloaded using the ticker:
BTC-USD
The raw Bitcoin dataset contains:
The same process was applied to the external predictor datasets to create a consistent financial dataset for forecasting.
Before integration, each dataset underwent validation procedures including:
The cleaned datasets were then saved into the processed data directory for use in subsequent forecasting stages.
# Load cleaned datasets
bitcoin <- read_csv(
"data_processed/bitcoin_clean.csv",
show_col_types = FALSE
)
gold <- read_csv(
"data_processed/gold_clean.csv",
show_col_types = FALSE
)
vix <- read_csv(
"data_processed/vix_clean.csv",
show_col_types = FALSE
)
treasury <- read_csv(
"data_processed/treasury10y_clean.csv",
show_col_types = FALSE
)
# Display dataset structure
tibble(
Dataset = c(
"Bitcoin",
"Gold",
"VIX",
"10-Year Treasury Yield"
),
Observations = c(
nrow(bitcoin),
nrow(gold),
nrow(vix),
nrow(treasury)
)
)# A tibble: 4 × 2
Dataset Observations
<chr> <int>
1 Bitcoin 4346
2 Gold 3167
3 VIX 3169
4 10-Year Treasury Yield 3152
Before developing the forecasting model, all financial datasets underwent data cleaning and validation procedures.
The cleaning process was performed to ensure that the datasets were suitable for integration and machine-learning analysis.
The following validation procedures were conducted:
Each dataset was cleaned separately before being combined into the final forecasting dataset.
The Bitcoin dataset was cleaned by:
The cleaned Bitcoin dataset retained the following variables:
The same cleaning procedure was applied to the external predictors:
| Dataset | Cleaning Applied |
|---|---|
| Gold | Missing-value validation, duplicate-date checking, chronological arrangement |
| VIX | Missing-value validation, duplicate-date checking, chronological arrangement |
| 10-Year U.S. Treasury Yield | Missing-value validation, duplicate-date checking, chronological arrangement |
After individual dataset cleaning, the datasets were integrated using the common variable:
date
The integrated dataset combines:
The integrated dataset provides the information foundation for target construction, feature engineering, exploratory analysis, and machine-learning modeling.
Following integration, the Bitcoin log return target was constructed and aligned with the predictor variables.
The final integrated dataset was prepared for subsequent stages:
library(readr)
library(dplyr)
# Load cleaned datasets
btc <- read_csv(
"data_processed/bitcoin_clean.csv",
show_col_types = FALSE
)
gold <- read_csv(
"data_processed/gold_clean.csv",
show_col_types = FALSE
)
vix <- read_csv(
"data_processed/vix_clean.csv",
show_col_types = FALSE
)
treasury <- read_csv(
"data_processed/treasury10y_clean.csv",
show_col_types = FALSE
)
# Ensure date format
btc$date <- as.Date(btc$date)
gold$date <- as.Date(gold$date)
vix$date <- as.Date(vix$date)
treasury$date <- as.Date(treasury$date)
# Merge datasets by date
integrated_data <- btc |>
left_join(
gold,
by = "date"
) |>
left_join(
vix,
by = "date"
) |>
left_join(
treasury,
by = "date"
)
# Arrange chronologically
integrated_data <- integrated_data |>
arrange(date)
# Check structure
dim(integrated_data)[1] 4346 19
head(integrated_data)# A tibble: 6 × 19
date btc_open btc_high btc_low btc_close btc_volume btc_adjusted
<date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2014-09-17 466. 468. 452. 457. 21056800 457.
2 2014-09-18 457. 457. 413. 424. 34483200 424.
3 2014-09-19 424. 428. 385. 395. 37919700 395.
4 2014-09-20 395. 423. 390. 409. 36863600 409.
5 2014-09-21 408. 412. 393. 399. 26580100 399.
6 2014-09-22 399. 407. 397. 402. 24127600 402.
# ℹ 12 more variables: gold_open <dbl>, gold_high <dbl>, gold_low <dbl>,
# gold_close <dbl>, gold_volume <dbl>, gold_adjusted <dbl>, vix_open <dbl>,
# vix_high <dbl>, vix_low <dbl>, vix_close <dbl>, vix_adjusted <dbl>,
# treasury_10y <dbl>
Exploratory analysis was conducted to understand the characteristics of the final modeling sample before applying machine-learning techniques.
The analysis focuses on:
The purpose of this stage is to identify important patterns, assess data characteristics, and provide a foundation for the forecasting methodology.
The final modeling dataset contains the variables required for forecasting Bitcoin t+3 Log Return.
The predictor variables included in the final modeling dataset are:
| Predictor | Description |
|---|---|
| btc_log_return | Current Bitcoin log return |
| btc_return_lag1 | Bitcoin return lag 1 |
| btc_return_lag2 | Bitcoin return lag 2 |
| btc_return_lag3 | Bitcoin return lag 3 |
| btc_sma7 | Bitcoin 7-day moving average |
| btc_rsi14 | Bitcoin momentum indicator |
| btc_williams_r14 | Williams %R indicator |
| btc_obv | On-Balance Volume |
| btc_parkinson_vol7 | Parkinson volatility |
| gold_log_return | Gold return |
| vix_close | CBOE Volatility Index |
| treasury_10y | 10-Year U.S. Treasury Yield |
The final forecasting target is:
target_t3
representing the Bitcoin log return occurring three trading periods into the future.
The Bitcoin closing price trend was examined to understand historical market movement.
#| fig-cap: "Bitcoin Closing Price Over Time"
btc |>
ggplot(
aes(
x = date,
y = btc_close
)
) +
geom_line() +
labs(
title = "Bitcoin Closing Price",
x = "Date",
y = "Bitcoin Closing Price"
)The price trend provides an overview of Bitcoin’s historical market behavior and identifies periods of substantial price movement.
The distribution of Bitcoin log returns was examined to evaluate return behavior.
#| fig-cap: "Distribution of Bitcoin Log Returns"
model_data |>
ggplot(
aes(
x = btc_log_return
)
) +
geom_histogram(
bins = 50
) +
labs(
title = "Distribution of Bitcoin Log Returns",
x = "Log Return",
y = "Frequency"
)The return distribution analysis provides information regarding:
The forecasting target examined in this analysis is:
Bitcoin t+3 Log Return
#| fig-cap: "Distribution of Bitcoin t+3 Log Return"
model_data |>
ggplot(
aes(
x = target_t3
)
) +
geom_histogram(
bins = 50
) +
labs(
title = "Distribution of Bitcoin t+3 Log Return",
x = "Target Return",
y = "Frequency"
)Understanding the target distribution is important because machine-learning models are trained to predict this future return outcome.
The forecasting framework incorporates external financial predictors:
These variables provide additional market information beyond Bitcoin-specific indicators.
predictor_summary <- model_data |>
summarise(
Gold = mean(gold_log_return, na.rm = TRUE),
VIX = mean(vix_close, na.rm = TRUE),
Treasury = mean(treasury_10y, na.rm = TRUE)
)
predictor_summary# A tibble: 1 × 3
Gold VIX Treasury
<dbl> <dbl> <dbl>
1 0.000427 18.3 2.72
Correlation analysis was performed to examine relationships between predictors and the forecasting target.
#| label: correlation-analysis
correlation_matrix <- model_data |>
select(
btc_log_return,
btc_return_lag1,
btc_return_lag2,
btc_return_lag3,
btc_sma7,
btc_rsi14,
btc_williams_r14,
btc_obv,
btc_parkinson_vol7,
gold_log_return,
vix_close,
treasury_10y,
target_t3
) |>
cor(
use = "complete.obs"
)
round(
correlation_matrix,
3
) btc_log_return btc_return_lag1 btc_return_lag2
btc_log_return 1.000 -0.026 -0.009
btc_return_lag1 -0.026 1.000 0.004
btc_return_lag2 -0.009 0.004 1.000
btc_return_lag3 0.018 -0.003 0.006
btc_sma7 -0.033 -0.020 -0.005
btc_rsi14 0.364 0.316 0.290
btc_williams_r14 -0.431 -0.318 -0.277
btc_obv -0.002 0.002 0.017
btc_parkinson_vol7 -0.010 -0.040 -0.033
gold_log_return 0.091 0.035 -0.004
vix_close -0.040 -0.037 -0.043
treasury_10y -0.032 -0.021 -0.010
target_t3 0.023 0.018 0.026
btc_return_lag3 btc_sma7 btc_rsi14 btc_williams_r14 btc_obv
btc_log_return 0.018 -0.033 0.364 -0.431 -0.002
btc_return_lag1 -0.003 -0.020 0.316 -0.318 0.002
btc_return_lag2 0.006 -0.005 0.290 -0.277 0.017
btc_return_lag3 1.000 -0.018 0.271 -0.253 -0.006
btc_sma7 -0.018 1.000 -0.049 0.017 0.783
btc_rsi14 0.271 -0.049 1.000 -0.810 0.013
btc_williams_r14 -0.253 0.017 -0.810 1.000 -0.023
btc_obv -0.006 0.783 0.013 -0.023 1.000
btc_parkinson_vol7 -0.036 -0.091 -0.088 0.099 -0.003
gold_log_return -0.039 0.035 0.035 -0.062 0.023
vix_close -0.052 0.047 -0.192 0.102 0.236
treasury_10y -0.012 0.629 -0.082 0.055 0.309
target_t3 0.028 -0.040 0.050 -0.040 -0.034
btc_parkinson_vol7 gold_log_return vix_close treasury_10y
btc_log_return -0.010 0.091 -0.040 -0.032
btc_return_lag1 -0.040 0.035 -0.037 -0.021
btc_return_lag2 -0.033 -0.004 -0.043 -0.010
btc_return_lag3 -0.036 -0.039 -0.052 -0.012
btc_sma7 -0.091 0.035 0.047 0.629
btc_rsi14 -0.088 0.035 -0.192 -0.082
btc_williams_r14 0.099 -0.062 0.102 0.055
btc_obv -0.003 0.023 0.236 0.309
btc_parkinson_vol7 1.000 -0.010 0.156 -0.199
gold_log_return -0.010 1.000 0.003 0.013
vix_close 0.156 0.003 1.000 -0.203
treasury_10y -0.199 0.013 -0.203 1.000
target_t3 0.020 0.017 -0.026 -0.027
target_t3
btc_log_return 0.023
btc_return_lag1 0.018
btc_return_lag2 0.026
btc_return_lag3 0.028
btc_sma7 -0.040
btc_rsi14 0.050
btc_williams_r14 -0.040
btc_obv -0.034
btc_parkinson_vol7 0.020
gold_log_return 0.017
vix_close -0.026
treasury_10y -0.027
target_t3 1.000
Correlation analysis provides an initial assessment of whether predictors demonstrate potential relationships with the forecasting target.
Multicollinearity analysis was performed to evaluate whether predictors contain highly overlapping information.
Understanding predictor relationships is important because excessive correlation between predictors may influence model interpretation.
# Display predictor correlation matrix
predictor_correlation <- model_data |>
select(
btc_log_return,
btc_return_lag1,
btc_return_lag2,
btc_return_lag3,
btc_sma7,
btc_rsi14,
btc_williams_r14,
btc_obv,
btc_parkinson_vol7,
gold_log_return,
vix_close,
treasury_10y
) |>
cor(
use = "complete.obs"
)
round(
predictor_correlation,
3
) btc_log_return btc_return_lag1 btc_return_lag2
btc_log_return 1.000 -0.026 -0.009
btc_return_lag1 -0.026 1.000 0.004
btc_return_lag2 -0.009 0.004 1.000
btc_return_lag3 0.018 -0.003 0.006
btc_sma7 -0.033 -0.020 -0.005
btc_rsi14 0.364 0.316 0.290
btc_williams_r14 -0.431 -0.318 -0.277
btc_obv -0.002 0.002 0.017
btc_parkinson_vol7 -0.010 -0.040 -0.033
gold_log_return 0.091 0.035 -0.004
vix_close -0.040 -0.037 -0.043
treasury_10y -0.032 -0.021 -0.010
btc_return_lag3 btc_sma7 btc_rsi14 btc_williams_r14 btc_obv
btc_log_return 0.018 -0.033 0.364 -0.431 -0.002
btc_return_lag1 -0.003 -0.020 0.316 -0.318 0.002
btc_return_lag2 0.006 -0.005 0.290 -0.277 0.017
btc_return_lag3 1.000 -0.018 0.271 -0.253 -0.006
btc_sma7 -0.018 1.000 -0.049 0.017 0.783
btc_rsi14 0.271 -0.049 1.000 -0.810 0.013
btc_williams_r14 -0.253 0.017 -0.810 1.000 -0.023
btc_obv -0.006 0.783 0.013 -0.023 1.000
btc_parkinson_vol7 -0.036 -0.091 -0.088 0.099 -0.003
gold_log_return -0.039 0.035 0.035 -0.062 0.023
vix_close -0.052 0.047 -0.192 0.102 0.236
treasury_10y -0.012 0.629 -0.082 0.055 0.309
btc_parkinson_vol7 gold_log_return vix_close treasury_10y
btc_log_return -0.010 0.091 -0.040 -0.032
btc_return_lag1 -0.040 0.035 -0.037 -0.021
btc_return_lag2 -0.033 -0.004 -0.043 -0.010
btc_return_lag3 -0.036 -0.039 -0.052 -0.012
btc_sma7 -0.091 0.035 0.047 0.629
btc_rsi14 -0.088 0.035 -0.192 -0.082
btc_williams_r14 0.099 -0.062 0.102 0.055
btc_obv -0.003 0.023 0.236 0.309
btc_parkinson_vol7 1.000 -0.010 0.156 -0.199
gold_log_return -0.010 1.000 0.003 0.013
vix_close 0.156 0.003 1.000 -0.203
treasury_10y -0.199 0.013 -0.203 1.000
The exploratory analysis provides the statistical foundation required before proceeding to feature engineering validation and machine-learning model development.
Feature engineering was conducted to transform the available financial data into variables that can be used by the machine-learning forecasting models.
The objective of feature engineering is to create meaningful predictors that represent different characteristics of Bitcoin market behavior, including:
All forecasting models use the same predictor set to ensure that performance differences reflect the modeling approach rather than differences in available information.
The final predictor set consists of 12 variables representing Bitcoin-specific information and external financial market information.
| Feature | Category | Financial Rationale |
|---|---|---|
| btc_log_return | Current Return | Captures the most recent Bitcoin return information available at the forecast origin |
| btc_return_lag1 | Required Lag | Captures short-term return persistence or reversal |
| btc_return_lag2 | Required Lag | Provides additional short-term return history |
| btc_return_lag3 | Required Lag | Extends return-memory structure to three periods |
| btc_sma7 | Moving Average | Represents short-term price trend and smooths price fluctuations |
| btc_rsi14 | Momentum Indicator | Measures recent price momentum and balance between upward and downward movements |
| btc_williams_r14 | Advanced Feature | Measures current price position relative to recent high-low range |
| btc_obv | Advanced Feature | Combines price direction and trading volume to capture buying and selling pressure |
| btc_parkinson_vol7 | Student-Designed Feature | Captures short-term volatility using Bitcoin high-low price ranges |
| gold_log_return | External Predictor | Captures movements in Gold as an external financial-market predictor |
| vix_close | External Predictor | Represents market-implied volatility and risk sentiment |
| treasury_10y | External Predictor | Represents long-term interest-rate environment and financial conditions |
The first lag feature captures the Bitcoin log return from the previous period.
[ Lag_1 = Return_{t-1} ]
This allows the model to evaluate whether recent Bitcoin return behavior contains information regarding future returns.
The second lag feature extends the return history:
[ Lag_2 = Return_{t-2} ]
This provides additional short-term market information.
The third lag feature captures a longer short-term return pattern:
[ Lag_3 = Return_{t-3} ]
Together, these lag variables represent the return-memory structure of Bitcoin.
The model includes a 7-period simple moving average:
[ SMA_7 ]
The moving average represents short-term price trends by smoothing daily Bitcoin price fluctuations.
The Relative Strength Index:
[ RSI(14) ]
is included as a momentum indicator.
RSI measures recent price momentum and evaluates the balance between upward and downward price movements.
Williams %R is calculated using Bitcoin high, low, and closing prices.
The indicator measures the location of the current price relative to its recent high-low trading range.
This provides additional information regarding short-term price positioning.
On-Balance Volume combines:
The purpose of OBV is to capture potential buying and selling pressure in the market.
Parkinson volatility was included as a student-designed feature.
Unlike traditional close-to-close volatility measures, Parkinson volatility uses the intraday high-low price range.
The feature captures volatility information that may not be fully represented by closing-price returns.
The implementation uses:
The forecasting framework also incorporates external market variables.
Gold log return is included as an external financial-market predictor.
It captures possible relationships between Bitcoin and movements in another major financial asset.
The CBOE Volatility Index (VIX) is included to represent market-implied volatility and overall risk sentiment.
The 10-Year U.S. Treasury Yield represents:
# Load engineered dataset
feature_data <- read_csv(
"data_processed/model_data.csv",
show_col_types = FALSE
)
# Display final predictors
predictor_names <- c(
"btc_log_return",
"btc_return_lag1",
"btc_return_lag2",
"btc_return_lag3",
"btc_sma7",
"btc_rsi14",
"btc_williams_r14",
"btc_obv",
"btc_parkinson_vol7",
"gold_log_return",
"vix_close",
"treasury_10y"
)
feature_data |>
select(
all_of(predictor_names)
) |>
head()# A tibble: 6 × 12
btc_log_return btc_return_lag1 btc_return_lag2 btc_return_lag3 btc_sma7
<dbl> <dbl> <dbl> <dbl> <dbl>
1 -0.00864 0.0301 -0.00455 -0.0575 391.
2 -0.0225 -0.00864 0.0301 -0.00455 386.
3 -0.0424 -0.0225 -0.00864 0.0301 380.
4 0.0294 -0.0257 -0.0891 -0.0424 355.
5 0.0183 0.0294 -0.0257 -0.0891 348.
6 0.0486 0.0183 0.0294 -0.0257 343.
# ℹ 7 more variables: btc_rsi14 <dbl>, btc_williams_r14 <dbl>, btc_obv <dbl>,
# btc_parkinson_vol7 <dbl>, gold_log_return <dbl>, vix_close <dbl>,
# treasury_10y <dbl>
The completed feature set provides the information framework used by all machine-learning forecasting models in the subsequent modeling stage.
The machine-learning methodology was designed to forecast the Bitcoin t+3 Log Return using a leakage-safe financial forecasting framework.
The modeling process was structured to ensure that:
The methodology consists of:
Financial data are time-dependent; therefore, the dataset was split chronologically rather than randomly.
The dataset was divided into:
The training dataset was used for:
The testing dataset remained untouched until final model evaluation.
This approach ensures that the evaluation process reflects a realistic forecasting environment where historical information is used to predict future observations.
Because the forecasting target represents Bitcoin return occurring at t+3, special attention was given to preventing target leakage.
Target leakage occurs when information from the future becomes available during model training, resulting in unrealistic performance estimates.
To prevent leakage:
The final modeling framework therefore ensures that only information available at time t is used to forecast the return occurring at t+3.
Hyperparameter tuning was performed using rolling-origin time-series cross-validation.
Unlike traditional random cross-validation, rolling-origin validation maintains the chronological structure of financial data.
The validation process repeatedly:
This approach provides a more realistic estimate of forecasting performance under changing market conditions.
Six forecasting models were developed and compared:
| Model | Description |
|---|---|
| Linear Regression | Linear benchmark model |
| Decision Tree | Tree-based nonlinear model |
| Random Forest | Ensemble tree model |
| XGBoost | Gradient boosting model |
| Support Vector Regression | Kernel-based regression model |
| Artificial Neural Network | Neural-network forecasting model |
The purpose of including multiple models is to compare different modeling approaches and identify the forecasting model with the strongest out-of-sample performance.
The models were trained using the same:
The final predictor set consisted of the 12 engineered variables developed in the Feature Engineering stage.
model_design <- tibble(
"Design Element" = c(
"Target Asset",
"Forecasting Target",
"Training/Test Split",
"Validation Method",
"Number of Predictors",
"Number of Models"
),
Specification = c(
"Bitcoin (BTC-USD)",
"Bitcoin t+3 Log Return",
"Chronological 80% / 20%",
"Rolling-origin time-series cross-validation",
"12 Predictors",
"6 Machine-learning models"
)
)
knitr::kable(model_design)| Design Element | Specification |
|---|---|
| Target Asset | Bitcoin (BTC-USD) |
| Forecasting Target | Bitcoin t+3 Log Return |
| Training/Test Split | Chronological 80% / 20% |
| Validation Method | Rolling-origin time-series cross-validation |
| Number of Predictors | 12 Predictors |
| Number of Models | 6 Machine-learning models |
# Load training and testing datasets
train_data <- read_csv(
"data_processed/train_data.csv",
show_col_types = FALSE
)
test_data <- read_csv(
"data_processed/test_data.csv",
show_col_types = FALSE
)
# Check dataset dimensions
dim(train_data)[1] 2362 15
dim(test_data)[1] 592 15
The completed machine-learning methodology provides a reproducible forecasting framework where multiple models are trained under the same conditions and evaluated using out-of-sample financial forecasting performance.
The six forecasting models were evaluated using out-of-sample predictions generated from the untouched testing dataset.
The evaluation compares the forecasting capability of each model in predicting:
Bitcoin t+3 Log Return
The models were evaluated using the following performance metrics:
The evaluation process determines the predictive-performance leader based on forecasting error and directional prediction performance.
Root Mean Squared Error measures the square root of the average squared difference between actual and predicted values.
[ RMSE = ]
A lower RMSE indicates better forecasting performance.
RMSE gives greater importance to larger forecast errors because the errors are squared.
Mean Absolute Error measures the average absolute difference between actual and predicted values.
[ MAE= _{t=1}^{n} |y_t-| ]
A lower MAE indicates that the model produces smaller average forecasting errors.
R-squared measures the proportion of variation in the forecasting target explained by the model.
[ R^2= 1- { (y_t-{y})^2 } ]
However, R² should not be used as the only basis for selecting a forecasting model, especially for out-of-sample financial return forecasting.
Directional Accuracy measures whether the predicted return direction matches the actual return direction.
A higher directional accuracy indicates better ability to identify whether Bitcoin returns move upward or downward.
The model performance comparison is presented below.
performance_summary <- read_csv(
"outputs/tables/performance_summary.csv",
show_col_types = FALSE
)
knitr::kable(
performance_summary,
digits = 5
)| Performance_Leader | RMSE | MAE | R2 | Directional_Accuracy | Training_Time_Seconds | Selection_Status |
|---|---|---|---|---|---|---|
| Decision Tree | 0.02371 | 0.01634 | NA | 51.68919 | 1.989 | Performance leader only; statistical superiority requires Diebold-Mariano testing. |
Models were ranked based primarily on forecasting error performance.
model_ranking <- read_csv(
"outputs/tables/model_ranking.csv",
show_col_types = FALSE
)
knitr::kable(
model_ranking |>
select(
Performance_Rank,
Model,
RMSE,
MAE,
R2,
Directional_Accuracy
),
digits = 5
)| Performance_Rank | Model | RMSE | MAE | R2 | Directional_Accuracy |
|---|---|---|---|---|---|
| 1 | Decision Tree | 0.02371 | 0.01634 | NA | 51.68919 |
| 2 | Support Vector Regression | 0.02378 | 0.01655 | 0.00082 | 48.81757 |
| 3 | XGBoost | 0.02403 | 0.01656 | 0.01384 | 47.46622 |
| 4 | Random Forest | 0.02514 | 0.01821 | 0.00009 | 49.66216 |
| 5 | Artificial Neural Network | 0.02673 | 0.02030 | 0.00665 | 48.31081 |
| 6 | Linear Regression | 0.02736 | 0.02098 | 0.00626 | 48.31081 |
#| fig-cap: "RMSE Comparison Across Forecasting Models"
# Load model ranking results for rendering
model_ranking <- read_csv(
"outputs/tables/model_ranking.csv",
show_col_types = FALSE
)
ggplot(
model_ranking,
aes(
x = reorder(Model, RMSE),
y = RMSE
)
) +
geom_col() +
coord_flip() +
labs(
title = "RMSE Comparison Across Forecasting Models",
x = "Model",
y = "RMSE"
)#| fig-cap: "Directional Accuracy Comparison Across Forecasting Models"
# Load model ranking results for rendering
model_ranking <- read_csv(
"outputs/tables/model_ranking.csv",
show_col_types = FALSE
)
ggplot(
model_ranking,
aes(
x = reorder(Model, Directional_Accuracy),
y = Directional_Accuracy
)
) +
geom_col() +
coord_flip() +
labs(
title = "Directional Accuracy Comparison Across Forecasting Models",
x = "Model",
y = "Directional Accuracy (%)"
)The out-of-sample evaluation results demonstrate differences in forecasting performance across the six machine-learning models.
Based on the numerical performance comparison, the Decision Tree model achieved the strongest overall forecasting performance and was identified as the predictive-performance leader.
The evaluation considered:
However, model ranking based only on forecasting metrics does not establish statistical superiority.
Although the Decision Tree model achieved the strongest numerical performance, additional statistical validation is required to determine whether the observed differences in forecasting accuracy are statistically meaningful.
Therefore, the next stage applies the Diebold-Mariano Test to compare forecast accuracy differences between competing models.
Although model performance metrics provide a numerical ranking of forecasting models, differences in RMSE, MAE, and Directional Accuracy alone do not determine whether one model is statistically superior to another.
Therefore, the Diebold-Mariano Test was applied to evaluate whether differences in forecasting accuracy between competing models are statistically meaningful.
The test compares forecast errors from competing models and determines whether one model provides significantly different predictive accuracy.
The Diebold-Mariano Test was conducted to:
The comparison was performed using the same out-of-sample forecast period and the same forecasting target:
Bitcoin t+3 Log Return
The Diebold-Mariano Test evaluates the following hypotheses:
[ H_0: ]
This means that there is no statistically significant difference between the forecast accuracy of the two models.
[ H_1: ]
This means that the forecast accuracy between the two models is statistically different.
The Diebold-Mariano comparison uses squared-error loss.
The forecast error is calculated as:
[ e_t = y_t- ]
where:
The loss difference between two models is evaluated to determine whether one model produces statistically different forecast errors.
The statistical significance level used in this analysis is:
[ = 0.05 ]
The decision rule is:
| Condition | Decision |
|---|---|
| p-value < 0.05 | Reject H₀ |
| p-value ≥ 0.05 | Do not reject H₀ |
Rejecting H₀ indicates evidence that the two models have different predictive accuracy.
Failing to reject H₀ indicates insufficient evidence that the models have different predictive accuracy.
dm_pairwise_results <- read_csv(
"outputs/tables/dm_pairwise_results.csv",
show_col_types = FALSE
)
knitr::kable(
dm_pairwise_results,
digits = 5
)| Model_1 | Model_2 | RMSE_1 | RMSE_2 | MSE_1 | MSE_2 | DM_Statistic | p_value | Significance | Decision | Lower_Loss_Model | Statistical_Winner | DM_Direction | Interpretation |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Linear Regression | Decision Tree | 0.02736 | 0.02371 | 0.00075 | 0.00056 | 5.87363 | 0.00000 | *** | Reject H0 | Decision Tree | Decision Tree | Decision Tree has lower squared-error loss than Linear Regression | Reject H0. Decision Tree has statistically significantly lower squared-error loss than Linear Regression at the 5% significance level. |
| Linear Regression | Random Forest | 0.02736 | 0.02514 | 0.00075 | 0.00063 | 6.63854 | 0.00000 | *** | Reject H0 | Random Forest | Random Forest | Random Forest has lower squared-error loss than Linear Regression | Reject H0. Random Forest has statistically significantly lower squared-error loss than Linear Regression at the 5% significance level. |
| Linear Regression | XGBoost | 0.02736 | 0.02403 | 0.00075 | 0.00058 | 6.31982 | 0.00000 | *** | Reject H0 | XGBoost | XGBoost | XGBoost has lower squared-error loss than Linear Regression | Reject H0. XGBoost has statistically significantly lower squared-error loss than Linear Regression at the 5% significance level. |
| Linear Regression | Support Vector Regression | 0.02736 | 0.02378 | 0.00075 | 0.00057 | 7.21575 | 0.00000 | *** | Reject H0 | Support Vector Regression | Support Vector Regression | Support Vector Regression has lower squared-error loss than Linear Regression | Reject H0. Support Vector Regression has statistically significantly lower squared-error loss than Linear Regression at the 5% significance level. |
| Linear Regression | Artificial Neural Network | 0.02736 | 0.02673 | 0.00075 | 0.00071 | 11.23411 | 0.00000 | *** | Reject H0 | Artificial Neural Network | Artificial Neural Network | Artificial Neural Network has lower squared-error loss than Linear Regression | Reject H0. Artificial Neural Network has statistically significantly lower squared-error loss than Linear Regression at the 5% significance level. |
| Decision Tree | Random Forest | 0.02371 | 0.02514 | 0.00056 | 0.00063 | -3.46857 | 0.00056 | *** | Reject H0 | Decision Tree | Decision Tree | Decision Tree has lower squared-error loss than Random Forest | Reject H0. Decision Tree has statistically significantly lower squared-error loss than Random Forest at the 5% significance level. |
| Decision Tree | XGBoost | 0.02371 | 0.02403 | 0.00056 | 0.00058 | -1.81490 | 0.07005 | . | Fail to Reject H0 | Decision Tree | No statistically significant winner | Decision Tree has lower squared-error loss than XGBoost | Fail to reject H0. There is insufficient statistical evidence at the 5% level to conclude that the forecasting accuracy of Decision Tree and XGBoost differs. |
| Decision Tree | Support Vector Regression | 0.02371 | 0.02378 | 0.00056 | 0.00057 | -0.35574 | 0.72216 | NA | Fail to Reject H0 | Decision Tree | No statistically significant winner | Decision Tree has lower squared-error loss than Support Vector Regression | Fail to reject H0. There is insufficient statistical evidence at the 5% level to conclude that the forecasting accuracy of Decision Tree and Support Vector Regression differs. |
| Decision Tree | Artificial Neural Network | 0.02371 | 0.02673 | 0.00056 | 0.00071 | -5.26999 | 0.00000 | *** | Reject H0 | Decision Tree | Decision Tree | Decision Tree has lower squared-error loss than Artificial Neural Network | Reject H0. Decision Tree has statistically significantly lower squared-error loss than Artificial Neural Network at the 5% significance level. |
| Random Forest | XGBoost | 0.02514 | 0.02403 | 0.00063 | 0.00058 | 3.47216 | 0.00055 | *** | Reject H0 | XGBoost | XGBoost | XGBoost has lower squared-error loss than Random Forest | Reject H0. XGBoost has statistically significantly lower squared-error loss than Random Forest at the 5% significance level. |
| Random Forest | Support Vector Regression | 0.02514 | 0.02378 | 0.00063 | 0.00057 | 4.67012 | 0.00000 | *** | Reject H0 | Support Vector Regression | Support Vector Regression | Support Vector Regression has lower squared-error loss than Random Forest | Reject H0. Support Vector Regression has statistically significantly lower squared-error loss than Random Forest at the 5% significance level. |
| Random Forest | Artificial Neural Network | 0.02514 | 0.02673 | 0.00063 | 0.00071 | -5.36482 | 0.00000 | *** | Reject H0 | Random Forest | Random Forest | Random Forest has lower squared-error loss than Artificial Neural Network | Reject H0. Random Forest has statistically significantly lower squared-error loss than Artificial Neural Network at the 5% significance level. |
| XGBoost | Support Vector Regression | 0.02403 | 0.02378 | 0.00058 | 0.00057 | 1.63567 | 0.10244 | NA | Fail to Reject H0 | Support Vector Regression | No statistically significant winner | Support Vector Regression has lower squared-error loss than XGBoost | Fail to reject H0. There is insufficient statistical evidence at the 5% level to conclude that the forecasting accuracy of XGBoost and Support Vector Regression differs. |
| XGBoost | Artificial Neural Network | 0.02403 | 0.02673 | 0.00058 | 0.00071 | -5.62289 | 0.00000 | *** | Reject H0 | XGBoost | XGBoost | XGBoost has lower squared-error loss than Artificial Neural Network | Reject H0. XGBoost has statistically significantly lower squared-error loss than Artificial Neural Network at the 5% significance level. |
| Support Vector Regression | Artificial Neural Network | 0.02378 | 0.02673 | 0.00057 | 0.00071 | -6.60136 | 0.00000 | *** | Reject H0 | Support Vector Regression | Support Vector Regression | Support Vector Regression has lower squared-error loss than Artificial Neural Network | Reject H0. Support Vector Regression has statistically significantly lower squared-error loss than Artificial Neural Network at the 5% significance level. |
The pairwise comparison evaluates forecasting accuracy differences between each competing model combination.
dm_overall_summary <- read_csv(
"outputs/tables/dm_overall_summary.csv",
show_col_types = FALSE
)
knitr::kable(
dm_overall_summary,
digits = 5
)| Models | Total_Pairwise_Comparisons | Significant_Comparisons | Non_Significant_Comparisons | Significance_Level | Loss_Function | Power | Forecast_Horizon_h |
|---|---|---|---|---|---|---|---|
| 6 | 15 | 12 | 3 | 0.05 | Squared Error | 2 | 1 |
The overall summary provides a consolidated view of the statistical evidence across the forecasting models.
dm_model_summary <- read_csv(
"outputs/tables/dm_model_summary.csv",
show_col_types = FALSE
)
knitr::kable(
dm_model_summary,
digits = 5
)| Model | Comparisons | Significant_Wins | Significant_Losses | Non_Significant_Comparisons |
|---|---|---|---|---|
| Decision Tree | 5 | 3 | 0 | 2 |
| XGBoost | 5 | 3 | 0 | 2 |
| Support Vector Regression | 5 | 3 | 0 | 2 |
| Random Forest | 5 | 2 | 3 | 0 |
| Artificial Neural Network | 5 | 1 | 4 | 0 |
| Linear Regression | 5 | 0 | 5 | 0 |
The model-level summary identifies models that demonstrate statistically competitive forecasting performance.
dm_leader_comparisons <- read_csv(
"outputs/tables/dm_leader_comparisons.csv",
show_col_types = FALSE
)
knitr::kable(
dm_leader_comparisons,
digits = 5
)| Competitor | DM_Statistic | p_value | Decision | Leader_MSE | Competitor_MSE | Significant_Difference | Leader_Has_Lower_Loss | Leader_Significantly_Better | Competitor_Significantly_Better | Statistically_Competitive_With_Leader | Decision_Engine_Status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Linear Regression | 5.87363 | 0.00000 | Reject H0 | 0.00056 | 0.00075 | TRUE | TRUE | TRUE | FALSE | FALSE | Performance leader is significantly better |
| Random Forest | -3.46857 | 0.00056 | Reject H0 | 0.00056 | 0.00063 | TRUE | TRUE | TRUE | FALSE | FALSE | Performance leader is significantly better |
| XGBoost | -1.81490 | 0.07005 | Fail to Reject H0 | 0.00056 | 0.00058 | FALSE | TRUE | FALSE | FALSE | TRUE | Statistically competitive with performance leader |
| Support Vector Regression | -0.35574 | 0.72216 | Fail to Reject H0 | 0.00056 | 0.00057 | FALSE | TRUE | FALSE | FALSE | TRUE | Statistically competitive with performance leader |
| Artificial Neural Network | -5.26999 | 0.00000 | Reject H0 | 0.00056 | 0.00071 | TRUE | TRUE | TRUE | FALSE | FALSE | Performance leader is significantly better |
The Diebold-Mariano Test provides additional statistical evidence regarding model performance differences.
The test results determine whether the Decision Tree model’s numerical advantage represents statistically meaningful improvement or whether competing models remain statistically competitive.
A model with the strongest numerical performance does not automatically represent a statistically superior forecasting model.
Therefore, the final model selection considers:
The final decision is consolidated through the Forecast Decision Engine.
The Forecast Decision Engine consolidates the results from the forecasting framework into a final model selection process.
The decision engine integrates:
The purpose of the Forecast Decision Engine is to identify the final selected forecasting model and determine statistically competitive alternatives.
The final forecasting model selection does not rely on a single performance metric.
The decision process considers:
| Evaluation Component | Purpose |
|---|---|
| Model Performance | Identifies models with stronger numerical forecasting results |
| Diebold-Mariano Test | Determines whether performance differences are statistically meaningful |
| SHAP Analysis | Explains selected model behavior |
| Executive Recommendation | Translates forecasting evidence into investment interpretation |
The Forecast Decision Engine identified the following model:
forecast_decision_engine <- read_csv(
"outputs/tables/forecast_decision_engine.csv",
show_col_types = FALSE
)
knitr::kable(
forecast_decision_engine,
digits = 5
)| Performance_Leader | Selected_Model_for_SHAP | Statistically_Competitive_Models | Robustness_Check_Models | Significant_DM_Wins_of_Leader | Non_Significant_Leader_Comparisons | Significant_Losses_of_Leader | Decision_Rule | SHAP_Status |
|---|---|---|---|---|---|---|---|---|
| Decision Tree | Decision Tree | Decision Tree; XGBoost; Support Vector Regression | XGBoost; Support Vector Regression | 3 | 2 | 0 | Combine Step 07 predictive performance with pairwise Diebold-Mariano statistical validation. | Selected model proceeds to Step 09 SHAP analysis. |
The selected forecasting model represents the model that provides the strongest overall combination of:
forecast_decision_engine# A tibble: 1 × 9
Performance_Leader Selected_Model_for_SHAP Statistically_Competitive_Models
<chr> <chr> <chr>
1 Decision Tree Decision Tree Decision Tree; XGBoost; Support Ve…
# ℹ 6 more variables: Robustness_Check_Models <chr>,
# Significant_DM_Wins_of_Leader <dbl>,
# Non_Significant_Leader_Comparisons <dbl>,
# Significant_Losses_of_Leader <dbl>, Decision_Rule <chr>, SHAP_Status <chr>
The output consolidates the final decision based on the complete forecasting workflow.
The forecasting framework identified Decision Tree as the selected forecasting model.
The selection was based on the combination of:
The selected model is then passed forward to Explainable Artificial Intelligence analysis to determine how the model generates its predictions.
Although one model may be selected as the final forecasting model, other models may remain statistically competitive.
The Diebold-Mariano results are therefore considered together with model performance metrics to avoid selecting a model based only on numerical ranking.
Statistically competitive models provide alternative forecasting approaches that may demonstrate similar predictive ability.
The Forecast Decision Engine provides the final analytical transition from technical model evaluation toward investment interpretation.
The selected model is not considered a guaranteed predictor of future Bitcoin performance.
Instead, it functions as a forecasting decision-support tool that combines:
decision_engine <- read_csv(
"outputs/tables/forecast_decision_engine.csv",
show_col_types = FALSE
)
decision_engine |>
knitr::kable(
digits = 5
)| Performance_Leader | Selected_Model_for_SHAP | Statistically_Competitive_Models | Robustness_Check_Models | Significant_DM_Wins_of_Leader | Non_Significant_Leader_Comparisons | Significant_Losses_of_Leader | Decision_Rule | SHAP_Status |
|---|---|---|---|---|---|---|---|---|
| Decision Tree | Decision Tree | Decision Tree; XGBoost; Support Vector Regression | XGBoost; Support Vector Regression | 3 | 2 | 0 | Combine Step 07 predictive performance with pairwise Diebold-Mariano statistical validation. | Selected model proceeds to Step 09 SHAP analysis. |
Explainable Artificial Intelligence (XAI) analysis was conducted using SHAP (SHapley Additive exPlanations) to understand how the selected forecasting model generates predictions.
The Forecast Decision Engine identified the Decision Tree as the selected forecasting model.
SHAP analysis was applied to explain:
SHAP explains the contribution of each predictor variable to the model prediction.
The analysis provides transparency by showing how the selected Decision Tree model uses the engineered features to forecast:
Bitcoin t+3 Log Return
The purpose of SHAP is interpretation of model behavior.
SHAP does not establish financial or economic causality.
The results explain how the fitted model behaves based on the available predictors.
forecast_decision_engine <- read_csv(
"outputs/tables/forecast_decision_engine.csv",
show_col_types = FALSE
)
forecast_decision_engine# A tibble: 1 × 9
Performance_Leader Selected_Model_for_SHAP Statistically_Competitive_Models
<chr> <chr> <chr>
1 Decision Tree Decision Tree Decision Tree; XGBoost; Support Ve…
# ℹ 6 more variables: Robustness_Check_Models <chr>,
# Significant_DM_Wins_of_Leader <dbl>,
# Non_Significant_Leader_Comparisons <dbl>,
# Significant_Losses_of_Leader <dbl>, Decision_Rule <chr>, SHAP_Status <chr>
The selected model passed to SHAP analysis is:
Decision Tree
SHAP feature importance summarizes the average contribution of each predictor to the model predictions.
shap_feature_importance <- read_csv(
"outputs/tables/shap_feature_importance.csv",
show_col_types = FALSE
)
knitr::kable(
shap_feature_importance,
digits = 5
)| Rank | Feature | Mean_Absolute_SHAP |
|---|---|---|
| 1 | treasury_10y | 0.00045 |
| 2 | btc_log_return | 0.00000 |
| 3 | btc_return_lag1 | 0.00000 |
| 4 | btc_return_lag2 | 0.00000 |
| 5 | btc_return_lag3 | 0.00000 |
| 6 | btc_sma7 | 0.00000 |
| 7 | btc_rsi14 | 0.00000 |
| 8 | btc_williams_r14 | 0.00000 |
| 9 | btc_obv | 0.00000 |
| 10 | btc_parkinson_vol7 | 0.00000 |
| 11 | gold_log_return | 0.00000 |
| 12 | vix_close | 0.00000 |
load(
"outputs/plots/plot_shap_importance.RData"
)
plot_shap_importanceThe SHAP feature importance ranking identifies which predictors contribute most strongly to the Decision Tree forecasting behavior.
The highest-ranked predictors represent variables that have the greatest influence on the model output.
The SHAP summary plot provides information regarding:
load(
"outputs/plots/plot_shap_beeswarm.RData"
)
plot_shap_beeswarmThe beeswarm plot demonstrates how individual predictor values contribute positively or negatively to the Decision Tree prediction.
The SHAP waterfall plot explains an individual forecast prediction by showing how each predictor contributes to the final model output.
load(
"outputs/plots/plot_shap_waterfall.RData"
)
plot_shap_waterfallThe SHAP waterfall plot provides a local explanation of an individual Decision Tree prediction.
Each feature contribution represents how the predictor moves the model prediction away from the baseline prediction.
Positive SHAP values indicate predictors that increase the predicted Bitcoin t+3 Log Return, while negative SHAP values indicate predictors that decrease the prediction.
The waterfall plot demonstrates how the Decision Tree combines multiple predictor variables to generate a specific forecasting outcome.
The Explainable Artificial Intelligence analysis provides transparency regarding how the selected Decision Tree model generates predictions.
The results identify:
The SHAP analysis supports model interpretability by explaining model behavior.
However, SHAP values should not be interpreted as evidence of financial or economic causality.
The analysis explains what predictors the model uses when generating forecasts, but it does not establish why Bitcoin returns occur in financial markets.
shap_interpretation_summary <- read_csv(
"outputs/tables/shap_interpretation_summary.csv",
show_col_types = FALSE
)
knitr::kable(
shap_interpretation_summary,
digits = 5
)| Selected_Model | SHAP_Method | SHAP_Simulations | Top_Feature | Top_Mean_Absolute_SHAP | Tree_Splits | Constant_Prediction_Model | Interpretation | Causality_Warning |
|---|---|---|---|---|---|---|---|---|
| Decision Tree | Monte Carlo approximate SHAP using fastshap | 50 | treasury_10y | 0.00045 | 1 | FALSE | The selected Decision Tree uses the predictor variables to generate its forecasts. The most influential predictor by mean absolute SHAP is treasury_10y . SHAP values describe the behavior of the fitted model and should not be interpreted as evidence of causality. | SHAP explains how the selected model generated predictions; it does not prove economic or financial causality. |
The SHAP analysis provides evidence regarding how the selected Decision Tree model uses the available predictors.
The interpretation focuses on:
The SHAP results explain the fitted model behavior and provide interpretability for investment decision support.
However, SHAP values should not be interpreted as evidence of economic causality.
The analysis explains what the model uses, not why the financial market moves.
The final investment recommendation is developed by integrating the complete forecasting framework:
The recommendation reflects the predictive evidence generated by the machine-learning framework and should be interpreted as decision-support information rather than a standalone investment decision.
Based on the complete forecasting framework, the final recommendation is:
The Decision Tree model was identified as the selected forecasting model based on its overall forecasting performance among the evaluated machine-learning models.
However, the forecasting evidence does not provide sufficient support for a strong directional investment conclusion.
The selected model demonstrates predictive capability within the evaluated sample period; however, Bitcoin return forecasting remains challenging due to market uncertainty, changing market conditions, and the unpredictable nature of financial markets.
Therefore, the forecasting output is interpreted as a Neutral Forecasting Signal.
The Decision Tree model achieved the strongest numerical forecasting performance among the evaluated models based on:
The model was therefore selected as the preferred forecasting model within the evaluated framework.
The Diebold-Mariano Test was conducted to determine whether differences in forecasting accuracy between competing models were statistically meaningful.
The statistical evidence was considered together with model performance results to avoid selecting a model based solely on numerical ranking.
SHAP analysis was conducted to understand how the selected Decision Tree model generates predictions.
The analysis identified the contribution and importance of predictor variables used by the model.
The SHAP results improve transparency by explaining model behavior.
However, SHAP values do not establish financial or economic causality.
The forecasting framework provides useful information regarding Bitcoin t+3 Log Return behavior.
The selected Decision Tree model demonstrates predictive value within the available dataset; however, the evidence should be interpreted cautiously.
The recommendation is therefore classified as:
Neutral Forecasting Signal
This indicates that the model provides analytical support for investment evaluation but does not generate a sufficiently strong signal to justify a definitive directional position.
The forecasting framework should be used together with broader financial analysis, market conditions, and investor-specific considerations.
Although the forecasting framework provides a structured approach for predicting Bitcoin t+3 Log Return, several limitations must be considered when interpreting the results.
The model outputs should be treated as predictive information and decision-support evidence rather than definitive explanations of future market behavior.
The forecasting models are developed using historical financial market data.
Machine-learning models identify patterns based on previous observations; however, historical relationships may not remain constant under future market conditions.
Changes in:
may influence future Bitcoin return behavior.
Bitcoin returns are influenced by numerous factors that may not be fully captured by the selected predictors.
Although the framework incorporates:
other economic, behavioral, technological, and market-specific factors may also influence Bitcoin performance.
The forecasting framework compares multiple machine-learning models and selects the model with the strongest performance within the evaluated dataset.
However, strong historical forecasting performance does not guarantee future forecasting accuracy.
Model performance may change when applied to different market environments or future observations.
The framework focuses specifically on:
Bitcoin t+3 Log Return
Therefore, the findings should not be interpreted as a prediction of:
The model is designed for short-horizon forecasting.
SHAP analysis improves transparency by explaining how the selected model uses predictor variables.
However:
SHAP explains model behavior rather than financial causality.
The identified influential predictors represent variables used by the model when generating forecasts, but they do not prove that these variables directly cause Bitcoin returns.
The forecasting framework provides analytical support for investment evaluation.
However, investment decisions should also consider:
The model should therefore be used as a decision-support framework rather than an independent investment decision mechanism.
This consulting report developed a financial forecasting and investment analytics framework for predicting Bitcoin t+3 Log Return using machine-learning models and explainable artificial intelligence techniques.
The analysis incorporated Bitcoin market information together with external financial predictors, including Gold, the CBOE Volatility Index (VIX), and the 10-Year U.S. Treasury Yield.
The forecasting framework followed a structured analytical process consisting of:
Among the evaluated machine-learning approaches, the Decision Tree model was identified as the selected forecasting model based on its overall forecasting performance within the evaluated framework.
The model evaluation considered:
The Diebold-Mariano Test was applied to determine whether observed differences in forecasting accuracy between models were statistically meaningful. This additional validation ensured that model selection was not based solely on numerical performance rankings.
SHAP analysis provided transparency regarding how the selected Decision Tree model generated predictions by identifying predictor contributions and explaining model behavior.
However, the results should be interpreted with appropriate caution. Forecasting results are predictive rather than causal, and SHAP explanations describe model behavior rather than establishing financial or economic causality.
Based on the complete forecasting framework, the final output was interpreted as a Neutral Forecasting Signal. The model provides useful decision-support information regarding Bitcoin t+3 Log Return behavior; however, it should not be used as a standalone investment decision mechanism.
Overall, this framework demonstrates how machine-learning forecasting, statistical validation, and explainable artificial intelligence can be integrated to support more transparent and informed financial decision-making.
Yahoo Finance. (2026). Historical market data for Bitcoin (BTC-USD), Gold (GC=F), and CBOE Volatility Index (VIX). Retrieved from Yahoo Finance.
Federal Reserve Bank of St. Louis. (2026). 10-Year Treasury Constant Maturity Rate (DGS10). Federal Reserve Economic Data (FRED).
Breiman, L. (2001). Random Forests. Machine Learning, 45, 5–32.
Chen, T., & Guestrin, C. (2016). XGBoost: A scalable tree boosting system. Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining.
Cortes, C., & Vapnik, V. (1995). Support-vector networks. Machine Learning, 20, 273–297.
Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning: Data Mining, Inference, and Prediction. Springer.
Diebold, F. X., & Mariano, R. S. (1995). Comparing predictive accuracy. Journal of Business & Economic Statistics, 13(3), 253–263.
Lundberg, S. M., & Lee, S. I. (2017). A unified approach to interpreting model predictions. Advances in Neural Information Processing Systems.
R Core Team. (2026). R: A language and environment for statistical computing.
RStudio Team. (2026). RStudio: Integrated Development Environment for R.
Tidymodels. (2026). Tidymodels: A collection of packages for modeling and machine learning using tidyverse principles.
The analysis was developed through a structured R workflow consisting of ten sequential scripts.
The scripts were organized as follows:
| Script | Purpose |
|---|---|
| 00_setup.R | Project setup, package loading, and folder creation |
| 01_data_acquisition.R | Financial data acquisition and cleaning |
| 02_target_and_integration.R | Target construction and dataset integration |
| 03_feature_engineering.R | Predictor feature creation |
| 04_exploratory_analysis.R | Exploratory data analysis |
| 05_model_setup.R | Training/testing split and validation framework |
| 06_model_training.R | Machine-learning model training |
| 07_model_evaluation.R | Forecast performance evaluation |
| 08_diebold_mariano.R | Statistical forecast comparison |
| 09_explainable_ai.R | SHAP explainability analysis |
| 10_executive_recommendation.R | Executive recommendation generation |
The complete analysis follows the sequence:
Data Acquisition
→ Data Cleaning
→ Target Construction
→ Feature Engineering
→ Exploratory Analysis
→ Machine Learning Modeling
→ Model Evaluation
→ Statistical Validation
→ Explainability Analysis
→ Executive Recommendation
# Load packages
library(tidyverse)
library(quantmod)
library(TTR)
library(randomForest)
library(xgboost)
library(kernlab)
library(nnet)
library(fastshap)
library(shapviz)
# Load final modeling dataset
model_data <- read_csv(
"data_processed/model_data.csv"
)
# Train/Test split
split_point <- floor(
0.80 * nrow(model_data)
)
train_data <- model_data[1:split_point, ]
test_data <- model_data[
(split_point + 1):nrow(model_data),
]
# Model training
# Linear Regression
# Decision Tree
# Random Forest
# XGBoost
# Support Vector Regression
# Artificial Neural Network
# Model evaluation
# RMSE
# MAE
# R-squared
# Directional Accuracy
# Statistical validation
# Diebold-Mariano Test
# Explainability
# SHAP Analysis