June 19, 2023

 Использование машинного обучения для создания торговой стратегии

Поблагодарить за перевод, можно подписавшись на канал Crypto_Track

Используйте Python и chatGPT для построения инновационных торговых стратегий

Мы хотим использовать машинное обучение для извлечения информации о будущих изменениях цены Bitcoin из данных о финансировании и объеме торгов, а также разработать прибыльную торговую стратегию.

Иллюстрация автора

Для этого мы будем использовать Python, sklearn и chatGPT. Код доступен на моем github.

Мы начнем с импорта всех соотвествующих модулей.

import pandas as pd
 import matplotlib.pyplot as plt
 from plotly.subplots import make_subplots
 import plotly.graph_objects as go
 import plotly.io as pio
 import plotly.offline as pyo
 from sklearn.tree import DecisionTreeClassifier
 from sklearn import tree
 import graphviz

Мы импортируем цену и данные о финансировании из файла csv и рассчитываем дельту объема и процентную доходность.

df = pd.read_csv('merged_df.csv')
 def _compute_vd_helper(volume: float, taker_buy_volume: float) -> float:
  vd = 2*taker_buy_volume - volume
  return vd
 df['volume_delta_base_asset'] = df.apply(lambda x: _compute_vd_helper(x.volume,
  x.taker_buy_base_asset_volume), axis=1)
 df['returns'] = (df.close - df.open)/df.open
 df['algo_funding'] = 100 * df['fundingRate']
 gain = pd.Series([1 if val > 0 else 0 for val in df.returns])

Мы используем библиотеку sklearn для применения метода машинного обучения с использованием дерева решений. Для данной цели выбираем объем, ставку финансирования и дельту объема в качестве матрицы характеристик и сохраняем их в датафрейме под названием Х. Наша целевая переменная равна 1, если данный текущий период времени дал положительный результат, и 0 в противном случае. Мы применяем разделение данных на обучающую и тестовую выборки в соотношении 80/20 и подгоняем их под дерево решений с максимальной глубиной 3. И последнее, но не менее важное: мы распечатываем и показываем график дерева решений. Этот код был адаптирован из кода, сгенерированного chatGPT, по следующему запросу:

" Как написать код для дерева решений из датафрейма pandas”

# Set the percentage of training data
 train_data_percentage = 0.5
 # Prepare your feature matrix and target variable
 X = df[['volume', 'algo_funding', 'volume_delta_base_asset']].shift(periods=-1)
 X = X.drop(X.index[-1])
 X = X.drop(X.index[0])
 # Target variable
 y = gain
 y = y.drop(y.index[-1])
 y = y.drop(y.index[0])
 # Split the data into training and testing sets
 # Calculate the number of samples for training based on the percentage
 num_train_samples = int(train_data_percentage * len(X))
 # Split the data into training and testing sets
 X_train = X[:num_train_samples]
 X_test = X[num_train_samples:]
 y_train = y[:num_train_samples]
 y_test = y[num_train_samples:]
 # Initialize the decision tree classifier
 clf = DecisionTreeClassifier(max_depth=3)
 # Train the decision tree classifier
 clf.fit(X_train, y_train)
 # Make predictions on the test set
 y_pred = clf.predict(X_test)
 # Visualize the tree structure
 dot_data = tree.export_graphviz(clf)
 graph = graphviz.Source(dot_data)
 graph.render('decision_tree', format='jpeg')
 graph.view() # Display the visualization

Мы видим, что третий лист слева обладает хорошей прогностической способностью – 70 выборок с положительным результатом из 114 выборок, или около 61%. Поэтому мы реализуем торговую стратегию с параметрами принятия решения, приводящими к этому результату, которые являются:

1.     Дельта объема больше, чем -4950,871

2.     Ставка финансирования меньше -0,003

Результирующее дерево решений (изображение создано автором)

Мы вычисляем новый столбец датафрейма, содержащий сигналы на покупку, где 1 означает покупку, а 0 означает отсутствие покупки на текущей свече. Мы предполагаем, что будем удерживать позицию ровно в течение одной свечи, поэтому доходность по одной сделке будет равна цене открытия минус цена закрытия свечи, на которой возникает сигнал. Мы строим данные ohlc на свечном графике с помощью plotly и указываем сигналы на покупку синими стрелками на графике.

df = df[-len(X_test):]
 df = df.reset_index(drop=True)
 weak_buy = lambda row: 1 if (row.algo_funding < -0.003
  and row.volume_delta_base_asset > -4950.871) else 0
 df['weak_buy'] = df.apply(weak_buy, axis=1).shift(1)
 # create subplots with two y-axes
 fig = make_subplots(specs=[[{"secondary_y": True}]])
 fig.add_trace(go.Candlestick(
  x=pd.to_datetime(df['open time'], unit='ms'),
  open=df.open,
  high=df.high,
  low=df.low,
  close=df.close,
  increasing=dict(line=dict(color='green')),
  decreasing=dict(line=dict(color='red')),
  name='Price')
 )
 fig.add_trace(go.Scatter(
  x=pd.to_datetime(df['open time'][df.weak_buy > 0], unit='ms'),
  y=-3000+df.low[df.weak_buy > 0],
  name='weak buy',
  mode='markers',
  marker=dict(
  symbol='triangle-up',
  size=10,
  color='blue',
  line=dict(width=1, color='blue'),
  )
 ))
 pio.write_image(fig, 'trade_entries_chart.jpeg', format='png')
 pyo.plot(fig, filename='plot.html', auto_open=True)

Мы видим, как при разворотах вниз и параболических движениях вверх генерируется мало сигналов. Большинство сигналов поступает при умеренных восходящих движениях или колебаниях рынков.

Синими стрелками отмечены торговые операции на тестовых данных (изображение создано автором)

Мы вычисляем кривую капитала нашей стратегии путем суммирования всех доходностей свечей, по которым наш алгоритм подал сигнал на покупку. Этот код был адаптирован из кода, сгенерированного chatGPT, по следующему запросу:

“Если у меня есть датафрейм со столбцом, который содержит сигналы на покупку для торговой стратегии, где 1 означает "покупать", а 0 означает "ничего не делать", и у меня есть второй столбец, содержащий процент доходности за этот период. Как я могу рассчитать кривую капитала для этой торговой стратегии и записать ее в третью колонку."

# Create a new column for the equity curve
 df['equity_curve'] = 1.0 # Initial value of 1.0
 # Iterate through the DataFrame rows
 for i in range(1, len(df)):
  # Compute equity curve based on buy signals and percentage returns
  if df.weak_buy.iloc[i] == 1:
  df.equity_curve.at[i] = df.equity_curve.iloc[i-1] * (1 + df.returns.iloc[i])
  else:
  df.equity_curve.at[i] = df.equity_curve.iloc[i-1]
 # Create a larger figure
 plt.figure(figsize=(18, 7)) # Set the width to 8 inches and height to 6 inches
 plt.grid(True)
 plt.plot(pd.to_datetime(df['open time'], unit='ms'), df.equity_curve, linewidth=2.5)
 plt.savefig('equity_curve.png')

Стратегия принесла бы доход в размере 24,39% за данный период времени, указанный в тестовых данных.

Результирующая кривая капитала по тестовым данным (изображение создано автором)

Мы можем вычислить следующие показатели производительности:

Mean: 0.04%
 Standard Deviation: 0.89%
 Max Drawdown: -22.80%
 Sharpe Ratio: 3.83
 Sortino Ratio: 6.55
 Omega Ratio: 1.54

Хотя максимальная просадка более чем на -22,80% может показаться большой, на крипторынках это вовсе не редкость.

Коэффициенты Шарпа и Сортино составляют 3,83 и 6,55, что, несомненно, является выдающимся показателем.

Не забудьте получить код с моего github, и желаю вам счастливой торговли.

Перевод подготовлен каналом Crypto_Track

Ссылка на статью: https://trading-data-analysis.pro/a-decision-tree-machine-learning-based-trading-strategy-returning-280-93-75509a2f6d96