<jupyter_start><jupyter_text>Import Price Data From Kraken API:<jupyter_code>import krakenex 
from pykrakenapi import KrakenAPI
import sys
import time
import urllib.request
import json
import requests
import pandas as pd
import numpy as np 

# import hvplot
# import hvplot.pandas
from IPython.display import Markdown

from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score, classification_report
from sklearn.decomposition import PCA
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestRegressor

from ta.momentum import RSIIndicator

pd.set_option("display.max_rows", 2000)
pd.set_option("display.max_columns", 2000)
pd.set_option("display.width", 1000)

import warnings
warnings.filterwarnings('ignore')
api = krakenex.API()
k = KrakenAPI(api)
ohlc = k.get_ohlc_data("BTCUSD")
def fetch_OHLC_data(symbol, timeframe):
    pair_split = symbol.split('/')
    symbol = pair_split[0] + pair_split[1]
    url = f'https://api.kraken.com/0/public/OHLC?pair={symbol}&interval={timeframe}'
    response = requests.get(url)
    if response.status_code == 200: 
        j = json.loads(response.text)
        result = j['result']
        keys = []
        for item in result:
            keys.append(item)
        if keys[0] != 'last':
            data = pd.DataFrame(result[keys[0]],
                                columns=['unix', 'open', 'high', 'low', 'close', 'vwap', 'volume', 'tradecount'])
        else:
            data = pd.DataFrame(result[keys[1]],
                                columns=['unix', 'open', 'high', 'low', 'close', 'vwap', 'volume', 'tradecount'])

        data['date'] = pd.to_datetime(data['unix'], unit='s')
        data['volume_from'] = data['volume'].astype(float) * data['close'].astype(float)
    return data
btc = fetch_OHLC_data(symbol="BTC/USD", timeframe="1440")
btc = btc.drop(columns=["unix", "open", "high", "low", "volume_from"])
btc = btc.set_index("date")
btc['close'] = btc['close'].astype(float)
btc['returns'] = btc.close.pct_change()
btc['change_in_price'] = btc['returns']
btc.change_in_price[btc.change_in_price > 0] = 1
btc.change_in_price[btc.change_in_price <= 0] = 0
btc.dropna(inplace=True)
btc['change_in_price'] = btc['change_in_price'].astype(int)
btc.head()<jupyter_output><empty_output><jupyter_text>Generate Quantitative Trading Signals:<jupyter_code>def generate_signals(btc):
    """Generates trading signals for a given dataset."""
    signals_df = btc.copy()
    # Set the short window and long windows
    short_window = 50
    long_window = 100

    # Generate the short and long moving averages signal (50 and 100 days, respectively)
    signals_df["SMA50"] = signals_df["close"].rolling(window=short_window).mean()
    signals_df["SMA100"] = signals_df["close"].rolling(window=long_window).mean()

    signals_df["long_sig"] = np.where(signals_df["SMA50"] > signals_df["SMA100"], 1.0, 0.0)
    signals_df["short_sig"] = np.where(signals_df["SMA50"] < signals_df["SMA100"], -1.0, 0.0)
    signals_df["SMA_signal"] = signals_df["long_sig"] + signals_df["short_sig"]
    
    # Calculate bollinger bands and upper and lowers bands of bollinger band and bollinger band signal
    signals_df['bollinger_mid_band'] = signals_df['close'].rolling(window=20).mean()
    signals_df['bollinger_std'] = signals_df['close'].rolling(window=20).std()

    signals_df['bollinger_upper_band']  = signals_df['bollinger_mid_band'] + (signals_df['bollinger_std'] * 1)
    signals_df['bollinger_lower_band']  = signals_df['bollinger_mid_band'] - (signals_df['bollinger_std'] * 1)

    signals_df['bollinger_long'] = np.where(signals_df['close'] < signals_df['bollinger_lower_band'], 1.0, 0.0)
    signals_df['bollinger_short'] = np.where(signals_df['close'] > signals_df['bollinger_upper_band'], -1.0, 0.0)
    signals_df['bollinger_signal'] = signals_df['bollinger_long'] + signals_df['bollinger_short']
    
    # Calculate RSI and RSI signals
    rsi_14 = RSIIndicator(close = signals_df.close, window = 14)
    signals_df["RSI"] = rsi_14.rsi()
    signals_df["RSI_long"] = np.where(signals_df["RSI"] < 30, 1.0, 0.0)
    signals_df["RSI_short"] = np.where(signals_df["RSI"] > 70, -1.0, 0.0)
    signals_df["RSI_signal"] = signals_df["RSI_long"] + signals_df["RSI_short"]
    
    # Calculate VWAP and VWAP signals
    signals_df['vwap'] = signals_df['vwap'].astype(float)
    signals_df['volume'] = signals_df['volume'].astype(float)
    signals_df["VWAP_long"] = np.where(signals_df["close"] < signals_df["vwap"], 1.0, 0.0)
    signals_df["VWAP_short"] = np.where(signals_df["close"] > signals_df["vwap"], -1.0, 0.0)
    signals_df["VWAP_signal"] = signals_df["VWAP_short"] + signals_df["VWAP_long"]
    signals_df["VWAP_signal"] = signals_df['VWAP_signal'].astype(float)
    
    return signals_df
all_sig = generate_signals(btc)
all_sig.tail()
all_sig.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 719 entries, 2019-07-02 to 2021-06-19
Data columns (total 25 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   close                 719 non-null    float64
 1   vwap                  719 non-null    float64
 2   volume                719 non-null    float64
 3   tradecount            719 non-null    int64  
 4   returns               719 non-null    float64
 5   change_in_price       719 non-null    int32  
 6   SMA50                 670 non-null    float64
 7   SMA100                620 non-null    float64
 8   long_sig              719 non-null    float64
 9   short_sig             719 non-null    float64
 10  SMA_signal            719 non-null    float64
 11  bollinger_mid_band    700 non-null    float64
 12  bollinger_std         700 non-null    float64
 13  bollinger_upper_band  700 non-null    float64
 14  bollinger_lower_band  700 non-null    float64
 15  boll[...]<jupyter_text>Random Forest With Raw Variables<jupyter_code>X = all_sig.copy()
X.dropna(inplace=True)
X.drop(columns=['close','returns','change_in_price'], inplace=True)
X.head(20)
y=all_sig['change_in_price'].values.reshape(-1,1)
y=y[99:]
y[:5]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=78)
scaler = StandardScaler()
X_scaler = scaler.fit(X_train)
X_train_scaled = X_scaler.transform(X_train)
X_test_scaled = X_scaler.transform(X_test)
rf_model = RandomForestClassifier(n_estimators=100, random_state=78)
rf_model = rf_model.fit(X_train_scaled, y_train)
predictions = rf_model.predict(X_test_scaled)
cm = confusion_matrix(y_test, predictions)
cm_df = pd.DataFrame(
    cm, index=["Actual 0", "Actual 1"], columns=["Predicted 0", "Predicted 1"]
)

acc_score = accuracy_score(y_test, predictions)
print("Confusion Matrix")
display(cm_df)
print(f"Accuracy Score : {acc_score}")
print("Classification Report")
print(classification_report(y_test, predictions))
importances = rf_model.feature_importances_
importances_sorted = sorted(zip(rf_model.feature_importances_, X.columns), reverse=True)
importances = pd.DataFrame(sorted(zip(rf_model.feature_importances_, X.columns), reverse=True))
importances.set_index(importances[1], inplace=True)
importances.drop(columns=1, inplace=True)
importances.rename(columns={0: 'Feature Importances'}, inplace=True)
importances_sorted = importances.sort_values(by='Feature Importances')
importances_sorted.plot(kind='barh', color='lightgreen', title= 'Features Importances', legend=False)<jupyter_output><empty_output><jupyter_text>Random Forest Predictions Selecting The Three Most Significant Signals<jupyter_code>all_sig.tail()
x_var_list = ['RSI_signal', 'bollinger_signal', 'VWAP_signal']
all_sig[x_var_list].tail()
all_sig.dropna(subset=x_var_list, inplace=True)
all_sig.dropna(subset=['returns'],inplace=True)
all_sig = all_sig.replace([np.inf, -np.inf], np.nan)
all_sig.head()
all_sig['Positive Return'] = np.where(all_sig['returns'] > 0, 1.0, 0.0)
all_sig.tail()
x_var = ['RSI_signal', 'bollinger_signal', 'VWAP_signal', 'Positive Return']
rf_df = all_sig[x_var]
rf_df.dropna(inplace=True)
X_test = rf_df[x_var_list]
y_test = rf_df["Positive Return"]
X_test.tail()
y_test.tail()
rf_reg = RandomForestRegressor(n_estimators = 100, max_depth=3, random_state = 78)
rf_reg.fit(X_test, y_test);
pred = rf_reg.predict(X_test)
rf_df["Predict"] = pred
rf_df.tail()
thresh = np.arange(0,1,0.1)
real_thresh = thresh[3]
rf_df['Binary Predict'] = np.where(rf_df["Predict"] > real_thresh, 1, 0)
rf_df.tail()
predicted = rf_df["Binary Predict"]
def assign_threshold(x):
    
    if x < 0.2:
        
        return 'sell'
    
    elif x >= 0.2 and x < 0.5:
        
        return 'hold'
    
    else:
                
        return 'buy'
rf_df['Recommend'] = rf_df['Predict'].apply(assign_threshold)
rf_df.tail(20)
Results = rf_df.drop(columns=['RSI_signal','bollinger_signal','VWAP_signal'])
Results.tail()
# Calculate cumulative return of model and plot the result
(1 + (all_sig['returns'] * Results['Binary Predict'])).cumprod().plot()
(1 + all_sig['returns']).cumprod().plot()
# Set initial capital allocation
initial_capital = 100000

# Plot cumulative return of model in terms of capital
cumulative_return_capital = initial_capital * (1 + (all_sig['returns'] * Results['Binary Predict'])).cumprod()
cumulative_return_capital.plot()
final_results = Results.drop(columns=['Positive Return','Predict','Binary Predict'])
final_results['close'] = all_sig['close']
final_results.head()
trial_results = final_results.copy()
buy_hold_results = final_results.copy()<jupyter_output><empty_output><jupyter_text>Algo Trading Strategy: 100% allocation<jupyter_code>wallet = 100000
equity = 0
num_coins = 0
wallet_history = []
equity_history = []
num_coins_history = []

for i in range(len(final_results)):


    if equity > 0 and final_results['Recommend'].iloc[i] == 'sell':

        wallet = num_coins * final_results['close'].iloc[i]
        equity = 0
        num_coins = 0
        
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)

    elif wallet > 0 and final_results['Recommend'].iloc[i] == 'buy':
        num_coins = wallet / final_results['close'].iloc[i]
        equity = num_coins * final_results['close'].iloc[i]
        wallet = 0
        
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)
            
    else:
        equity = num_coins * final_results['close'].iloc[i]
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)
        

final_results['wallet'] = wallet_history
final_results['share equity'] = equity_history
final_results['total equity'] = final_results['share equity'] + final_results['wallet']
final_results['num coins'] = num_coins_history

final_results.tail()
(final_results['total equity'] - 100000).plot(figsize=(20,10),ylabel='cumulative return')<jupyter_output><empty_output><jupyter_text>New Strategy: 20% allocation<jupyter_code>wallet = 100000
equity = 0
num_coins = 0
wallet_history = []
equity_history = []
num_coins_history = []
trade_per = 0.2

for i in range(len(trial_results)):
    
    if equity > 0 and trial_results['Recommend'].iloc[i] == 'sell':
        coin_change = (equity * trade_per) / trial_results['close'].iloc[i]
        wallet = wallet + (coin_change * trial_results['close'].iloc[i])
        num_coins = num_coins - coin_change
        equity = num_coins * trial_results['close'].iloc[i]
        
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)

    elif wallet > 0 and trial_results['Recommend'].iloc[i] == 'buy':
        coin_change = (wallet * trade_per) / trial_results['close'].iloc[i] 
        wallet = wallet - (wallet * trade_per)
        num_coins = num_coins + coin_change
        equity = num_coins * trial_results['close'].iloc[i]

        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)
                    
    else:
        equity = num_coins * trial_results['close'].iloc[i]
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)
        
trial_results['wallet'] = wallet_history
trial_results['share equity'] = equity_history
trial_results['total equity'] = trial_results['share equity'] + trial_results['wallet']
trial_results['num coins'] = num_coins_history
trial_results['portfolio daily returns'] = trial_results['total equity'].pct_change()
trial_results['portfolio cumulative returns'] = trial_results['portfolio daily returns'].cumprod()

trial_results.tail()
(trial_results['total equity'] - 100000).plot(figsize=(20,10),ylabel='cumulative return')<jupyter_output><empty_output><jupyter_text>Visualize Trading Strategy:<jupyter_code>rf_df['close'] = all_sig['close']

# Visualize exit position relative to close price
exit = rf_df[rf_df['VWAP_signal'] == -1.0]['close'].hvplot.scatter(
    color='red',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize entry position relative to close price
entry = rf_df[rf_df['VWAP_signal'] == 1.0]['close'].hvplot.scatter(
    color='green',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize close price for the investment
coin_close = rf_df[['close']].hvplot(
    line_color='lightgray',
    ylabel='Price in $',
    width=1000,
    height=400
)

vwap = all_sig[['vwap']].hvplot(ylabel='Price in $',
    width=1000,
    height=400
)

# Overlay plots
entry_exit_plot = coin_close * vwap * entry * exit
entry_exit_plot.opts(xaxis=None)
# Visualize exit position relative to close price
exit = all_sig[all_sig['bollinger_signal'] == -1.0]['close'].hvplot.scatter(
    color='red',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize entry position relative to close price
entry = all_sig[all_sig['bollinger_signal'] == 1.0]['close'].hvplot.scatter(
    color='green',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize close price for the investment
coin_close = rf_df[['close']].hvplot(
    line_color='lightgray',
    ylabel='Price in $',
    width=1000,
    height=400
)

bol_bands = all_sig[['bollinger_mid_band', 'bollinger_upper_band', 'bollinger_lower_band']].hvplot(
    ylabel='Price in $',
    width=1000,
    height=400
)

# Overlay plots
entry_exit_plot = coin_close * bol_bands * entry * exit
entry_exit_plot.opts(xaxis=None)

# Visualize exit position relative to close price
exit = all_sig[all_sig['RSI_signal'] == -1.0]['close'].hvplot.scatter(
    color='red',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize entry position relative to close price
entry = all_sig[all_sig['RSI_signal'] == 1.0]['close'].hvplot.scatter(
    color='green',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize close price for the investment
coin_close = rf_df[['close']].hvplot(
    line_color='lightgray',
    ylabel='Price in $',
    width=1000,
    height=400
)

RSI = all_sig[['RSI']].hvplot(
    ylabel='Price in $',
    width=1000,
    height=400
)

# Overlay plots
entry_exit_plot = coin_close * RSI * entry * exit
entry_exit_plot.opts(xaxis=None)
# Visualize exit position relative to close price
exit = rf_df[rf_df['Binary Predict'] == 0.0]['close'].hvplot.scatter(
    color='red',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize entry position relative to close price
entry = rf_df[rf_df['Binary Predict'] == 1.0]['close'].hvplot.scatter(
    color='green',
    legend=False,
    ylabel='Price in $',
    width=1000,
    height=400
)

# Visualize close price for the investment
coin_close = rf_df[['close']].hvplot(
    line_color='lightgray',
    ylabel='Price in $',
    width=1000,
    height=400
)

# Overlay plots
entry_exit_plot = coin_close * RSI * entry * exit
entry_exit_plot.opts(xaxis=None)

# Prepare DataFrame for metrics
metrics = [
    'Annual Return',
    'Cumulative Returns',
    'Annual Volatility',
    'Sharpe Ratio',
    'Sortino Ratio']

columns = ['Backtest']

# Initialize the DataFrame with index set to evaluation metrics and column as `Backtest` (just like PyFolio)
portfolio_evaluation_df = pd.DataFrame(index=metrics, columns=columns)
portfolio_evaluation_df
trial_results.head()
# Calculate cumulative return
portfolio_evaluation_df.loc['Cumulative Returns'] = trial_results['portfolio cumulative returns'][-1]

# Calculate annualized return
portfolio_evaluation_df.loc['Annual Return'] = (
    trial_results['portfolio daily returns'].mean() * 252
)

# Calculate annual volatility
portfolio_evaluation_df.loc['Annual Volatility'] = (
    trial_results['portfolio daily returns'].std() * np.sqrt(252)
)

# Calculate Sharpe Ratio
portfolio_evaluation_df.loc['Sharpe Ratio'] = (
    trial_results['portfolio daily returns'].mean() * 252) / (
    trial_results['portfolio daily returns'].std() * np.sqrt(252)
)

# Calculate Downside Return
sortino_ratio_df = trial_results[['portfolio daily returns']].copy()
sortino_ratio_df.loc[:,'Downside Returns'] = 0
target = 0
mask = sortino_ratio_df['portfolio daily returns'] < target
sortino_ratio_df.loc[mask, 'Downside Returns'] = sortino_ratio_df['portfolio daily returns']**2
portfolio_evaluation_df

# Calculate Sortino Ratio
down_stdev = np.sqrt(sortino_ratio_df['Downside Returns'].mean()) * np.sqrt(252)
expected_return = sortino_ratio_df['portfolio daily returns'].mean() * 252
sortino_ratio = expected_return/down_stdev

portfolio_evaluation_df.loc['Sortino Ratio'] = sortino_ratio
portfolio_evaluation_df.head()<jupyter_output><empty_output><jupyter_text>Buy and Hold Strategy for comparison<jupyter_code>wallet = 100000
equity = 0
num_coins = 0
wallet_history = []
equity_history = []
num_coins_history = []

for i in range(len(final_results)):
    
    if wallet > 0 and final_results['Recommend'].iloc[i] == 'buy':
        num_coins = wallet / buy_hold_results['close'].iloc[i]
        equity = num_coins * buy_hold_results['close'].iloc[i]
        wallet = 0
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)
    
    else:
        equity = num_coins * buy_hold_results['close'].iloc[i]
        wallet_history.append(wallet)
        equity_history.append(equity)
        num_coins_history.append(num_coins)

buy_hold_results['wallet'] = wallet_history
buy_hold_results['share equity'] = equity_history
buy_hold_results['total equity'] = final_results['share equity'] + final_results['wallet']
buy_hold_results['num coins'] = num_coins_history

buy_hold_results.tail()
(buy_hold_results["total equity"]-100000).plot(figsize = (20,10),ylabel='cumulative return')
comparison = pd.merge(buy_hold_results["total equity"],trial_results['total equity'],on='date')
comparison.columns = ['buy & hold','20% allocation']
comparison.plot(figsize=(20,10),ylabel='cumulative return')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13452145900446846, 'fraction_numerical': 0.025979424295957603, 'mean_word_length': 4.497572122250785, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 46, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '282793', 'license': 'MIT', 'n_tokens_mistral': 7041, 'n_tokens_neox': 6569, 'n_words': 1241, 'path': 'pricePredMaster.ipynb', 'repo_name': 'jusgou/pricePredictor', 'size': '19246'}