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

Автор:Доброта, Создано: 2019-08-21 13:50:23, Обновлено: 2023-10-19 21:01:31

img

Сочетание сделок является хорошим примером разработки стратегии сделок на основе математического анализа. В этой статье мы покажем, как использовать данные для создания и автоматизации стратегии сочетания сделок.

Принципы

假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.

Когда существует временная разница в ценах, на сделке будет продана отличная инвестиционная марка (высокая инвестиционная марка) и куплена некачественная инвестиционная марка (низкая инвестиционная марка). Вы можете быть уверены, что разница в прибыли между двумя инвестициями в конечном итоге будет вызвана падением отличной инвестиционной марки или восстановлением некачественной инвестиционной марки или обоими. Ваша сделка будет зарабатывать деньги во всех подобных сценариях.

Таким образом, двойная торговля является нейтральной для рынка стратегией торговли, которая позволяет трейдерам получать прибыль от практически любых рыночных условий: рост, падение или поперечное распределение.

Определение понятия: два предполагаемых показателя инвестиций

  • Мы создали нашу исследовательскую среду на квантовой платформе для изобретателей.

Во-первых, для того, чтобы работа шла гладко, нам нужно построить нашу исследовательскую среду, в которой мы будем использовать квантовую платформу для изобретателей.FMZ.COMПостроение исследовательской среды, в основном для использования платформы с удобным и быстрым интерфейсом API и полной упаковкой системы Docker.

В официальном названии платформы количественного измерения изобретателей система Docker называется системой хостеров.

Для того, чтобы узнать, как развернуть хостеров и ботов, обратитесь к моей предыдущей статье:https://www.fmz.com/bbs-topic/4140

Читатели, которые хотят купить хост для развертывания собственных облачных серверов, могут ознакомиться с этой статьей:https://www.fmz.com/bbs-topic/2848

После успешного развертывания хороших облачных сервисов и систем хостеров, следующим шагом будет установка самого большого храма Python: Anaconda.

Для реализации всех необходимых программных условий ("зависимость библиотеки, управление версиями и т. д.) самый простой способ - использовать Anaconda.

О том, как установить Anaconda, читайте в официальном руководстве:https://www.anaconda.com/distribution/

本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.

Вышеперечисленные основные работы также могут быть рассмотрены в моей предыдущей статье о том, как настроить среду Anaconda и две библиотеки numpy и pandas.https://www.fmz.com/digest-topic/4169

А теперь давайте попробуем реализовать в коде "двух гипотетических инвестиционных показателей".

import numpy as np
import pandas as pd

import statsmodels
from statsmodels.tsa.stattools import coint
# just set the seed for the random number generator
np.random.seed(107)

import matplotlib.pyplot as plt

Да, мы также будем использовать очень известную библиотеку таблиц в Python, matplotlib.

Давайте создадим X предполагаемого показателя инвестиций и смоделируем его ежедневный доход с помощью нормального распределения.

# Generate daily returns
Xreturns = np.random.normal(0, 1, 100) 
# sum them and shift all the prices up
X = pd.Series(np.cumsum(
    Xreturns), name='X') 
    + 50
X.plot(figsize=(15,7))
plt.show()

img

Инвестиционный индекс X, моделируемый с помощью нормального распределения для изображения его ежедневных доходов

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

noise = np.random.normal(0, 1, 100)
Y = X + 5 + noise
Y.name = 'Y'
pd.concat([X, Y], axis=1).plot(figsize=(15,7))
plt.show()

img

Совместные инвестиционные показатели X и Y

Совместная работа

协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:

Y = X + e

В данном случае, мы можем вычислить, что мы можем сделать, если у нас есть постоянная проницаемость, и e - шум.

Для пары сделок между двумя временными последовательностями это соотношение с течением времени должно совпадать с ожидаемыми значениями, т.е. они должны быть совпадающими. Временные последовательности, которые мы создали выше, совпадают.

(Y/X).plot(figsize=(15,7)) 
plt.axhline((Y/X).mean(), color='red', linestyle='--') 
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()

img

Соотношение и среднее значение между ценами двух совпадающих инвестиционных индикаторов

Координационные тесты

Есть удобный метод тестирования, используя statsmodels.tsa.stattools. Мы должны видеть очень низкое p-значение, потому что мы искусственно создали две серии данных, которые как можно больше совпадают.

# compute the p-value of the cointegration test
# will inform us as to whether the ratio between the 2 timeseries is stationary
# around its mean
score, pvalue, _ = coint(X,Y)
print pvalue

Результат: 1.81864477307e-17

Примечание: соотношение и интеграция

Соотношение и совпадение, хотя и похожи в теории, но не одинаковы. Давайте посмотрим на примеры соотношения, но не совпадения, и наоборот.

X.corr(Y)

Результат: 0.951.

Как мы ожидали, это очень высоко. Но что делать с двумя связанными, но несовместимыми сериями?

ret1 = np.random.normal(1, 1, 100)
ret2 = np.random.normal(2, 1, 100)

s1 = pd.Series( np.cumsum(ret1), name='X')
s2 = pd.Series( np.cumsum(ret2), name='Y')

pd.concat([s1, s2], axis=1 ).plot(figsize=(15,7))
plt.show()
print 'Correlation: ' + str(X_diverging.corr(Y_diverging))
score, pvalue, _ = coint(X_diverging,Y_diverging)
print 'Cointegration test p-value: ' + str(pvalue)

img

Две связанные серии (не объединенные)

Соответствующие коэффициенты: 0.998 П-значение совпадения: 0.258

Простыми примерами совпадений без корреляции являются последовательности нормального распределения и квадратные волны.

Y2 = pd.Series(np.random.normal(0, 1, 800), name='Y2') + 20
Y3 = Y2.copy()
Y3[0:100] = 30
Y3[100:200] = 10
Y3[200:300] = 30
Y3[300:400] = 10
Y3[400:500] = 30
Y3[500:600] = 10
Y3[600:700] = 30
Y3[700:800] = 10
Y2.plot(figsize=(15,7))
Y3.plot()
plt.ylim([0, 40])
plt.show()
# correlation is nearly zero
print 'Correlation: ' + str(Y2.corr(Y3))
score, pvalue, _ = coint(Y2,Y3)
print 'Cointegration test p-value: ' + str(pvalue)

img

Соответствие: 0.007546 П-значение сочетания: 0.0

В то время как ученые считают, что корреляция очень низкая, но p-значения показывают идеальную совместимость!

Как проводить сделку?

Поскольку две совпадающие временные последовательности (например, X и Y) параллельны и отклоняются друг от друга, иногда возникают ситуации с высокими и низкими коэффициентами. Мы совершаем параллельную сделку, покупая один и продавая другой. Таким образом, если оба коэффициента падают или растут вместе, мы не зарабатываем и не теряем, то есть мы являемся нейтральными на рынке.

Возвращаясь к Y = X + e в X и Y, чтобы соотношение ((Y / X) двигалось вокруг его среднего значения, мы зарабатываем на соотношении с возвращением среднего значения. Чтобы сделать это, мы обращаем внимание на ситуацию, когда X и Y очень далеко друг от друга, то есть порог слишком высок или слишком низкий:

  • Сделайте многопроцентный: это когда коэффициент очень мал и мы ожидаем, что он увеличится. В примере выше мы открываем позицию, сделав больше Y и сделав пустой X.

  • Коэффициент пустоты: это когда коэффициент очень большой и мы ожидаем, что он изменится в часы. В примере выше мы открываем позиции, пустоту Y и много X.

Обратите внимание, что у нас всегда есть гигантская гигантская позиция: если цена на покупку и убытки в торговом индексе снижается, то гигантская позиция будет зарабатывать, и наоборот. Таким образом, мы являемся иммунитетом к движению рынка в целом.

Если X и Y движутся по отношению друг к другу, мы получаем прибыль или убыток.

Использование данных для поиска поведения, аналогичного торговым показателям

Лучший способ сделать это - начать с того, что вы подозреваете, что может быть совпадением, и провести статистическое тестирование.Многократное отклонениеОн был убит в результате насилия.

Многократное отклонениеЭто означает, что вероятность ошибочного получения важных p-значений увеличивается при выполнении большого количества тестов, потому что нам нужно выполнять большое количество тестов. Если мы выполним 100 тестов на случайные данные, мы должны увидеть 5 p-значений ниже 0.05. Если вы собираетесь сравнить n параметров с целью проведения целого совпадения, то вы выполните n ((n-1) / 2 сравнения, и вы увидите много неправильных p-значений, которые увеличиваются с увеличением вашей пробной группы. Чтобы избежать этого, выберите несколько пар сделок, для которых у вас есть основания считать, что они могут быть совместными, и затем проверьте их отдельно.Многократное отклонение

Итак, давайте попробуем найти несколько торговых индексов, которые демонстрируют сходство. Давайте рассмотрим одну из баз крупных американских технологических акций в индексе S&P 500, которые работают в аналогичных сегментах рынка и имеют сходные цены.

Возвращается сочетание всех матриц, в которых сходство проверяется, с матрицами деления, матрицами с p-значениями, а также с матрицами с p-значениями меньшими чем 0.05.Это способ, который может иметь многочисленные отклонения в сравнении, поэтому им фактически требуется повторная проверка.В данной статье, чтобы упростить наше объяснение, мы предпочли игнорировать это в примерах.

def find_cointegrated_pairs(data):
    n = data.shape[1]
    score_matrix = np.zeros((n, n))
    pvalue_matrix = np.ones((n, n))
    keys = data.keys()
    pairs = []
    for i in range(n):
        for j in range(i+1, n):
            S1 = data[keys[i]]
            S2 = data[keys[j]]
            result = coint(S1, S2)
            score = result[0]
            pvalue = result[1]
            score_matrix[i, j] = score
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.02:
                pairs.append((keys[i], keys[j]))
    return score_matrix, pvalue_matrix, pairs

Примечание: мы включили в данные рыночные ориентиры (SPX) - рынок движет движением многих индикаторов торговли, и обычно вы можете найти два, казалось бы, совместимых индикатора торговли; но на самом деле они не совмещаются друг с другом, а совмещаются с рынком. Это называется смешанными переменными.

from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2007/12/01'
endDateStr = '2017/12/01'
cachedFolderName = 'yahooData/'
dataSetId = 'testPairsTrading'
instrumentIds = ['SPY','AAPL','ADBE','SYMC','EBAY','MSFT','QCOM',
                 'HPQ','JNPR','AMD','IBM']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')
data = ds.getBookDataByFeature()['Adj Close']
data.head(3)

img

Теперь давайте попробуем найти совместимые пары сделок с помощью нашего метода.

# Heatmap to show the p-values of the cointegration test
# between each pair of stocks
scores, pvalues, pairs = find_cointegrated_pairs(data)
import seaborn
m = [0,0.2,0.4,0.6,0.8,1]
seaborn.heatmap(pvalues, xticklabels=instrumentIds, 
                yticklabels=instrumentIds, cmap=’RdYlGn_r’, 
                mask = (pvalues >= 0.98))
plt.show()
print pairs
[('ADBE', 'MSFT')]

img

По-видимому, ADBE и MSFT сочетаются. Давайте посмотрим на цену, чтобы убедиться, что это действительно имеет смысл.

S1 = data['ADBE']
S2 = data['MSFT']
score, pvalue, _ = coint(S1, S2)
print(pvalue)
ratios = S1 / S2
ratios.plot()
plt.axhline(ratios.mean())
plt.legend([' Ratio'])
plt.show()

img

График соотношения цен между MSFT и ADBE за 2008-2017 годы

Это соотношение действительно выглядит как стабильное среднее значение. Абсолютные соотношения не очень полезны в статистике. Нам помогает стандартизировать наш сигнал, рассматривая их как z-соотношение.

Показатель Z (значение) = (значение среднее значение) / стандартное отклонение

Предупреждение

На самом деле, мы обычно пытаемся сделать некоторые расширения данных, но при условии, что они имеют нормальное распределение. Однако, многие финансовые данные не имеют нормального распределения, поэтому мы должны быть очень осторожны, чтобы не просто предположить нормальность или какое-либо конкретное распределение при создании статистических данных.

def zscore(series):
    return (series - series.mean()) / np.std(series)
zscore(ratios).plot()
plt.axhline(zscore(ratios).mean())
plt.axhline(1.0, color=’red’)
plt.axhline(-1.0, color=’green’)
plt.show()

img

Соотношение цен Z между MSFT и ADBE с 2008 по 2017 год

Теперь нам легче наблюдать, как соотношение движется вблизи среднего значения, но иногда бывает легко обнаружить большие различия от среднего значения, и мы можем использовать это.

Теперь, когда мы обсудили основы параллельных торговых стратегий и определили общие интегральные торговые показатели на основе исторических цен, давайте попробуем разработать торговый сигнал.

  • Сбор надежных данных и очистка данных

  • Создание функций из данных для распознавания торговых сигналов/логики

  • Функции могут быть движущимися средними или данными о ценах, соотношениями соотношений или более сложными сигналами - комбинируйте их, чтобы создать новые функции

  • С помощью этих функций генерируются торговые сигналы, которые указывают на то, что вы покупаете, продаёте или покупаете.

К счастью, у нас есть платформа для квантования изобретателей.fmz.comЭто огромное благословение для разработчиков стратегий, которые могут потратить все свои силы и время на разработку стратегии логики и расширение функциональности.

На платформе, где есть интерфейсы для основных бирж, нам нужно просто вызвать эти интерфейсы API, а остальная часть - логика реализации, которую уже отработали профессиональные команды.

Для полноты логики и объяснения принципов мы будем использовать эти базовые логики в виде коровьего откоса, но в практических операциях читатели могут сделать все четыре аспекта прямо с помощью количественного интерфейса API, созданного изобретателями.

Давайте начнем:

Шаг первый: задать свой вопрос

Здесь мы пытаемся создать сигнал, который скажет нам, будет ли этот коэффициент покупать или продавать в следующий момент, то есть наша прогнозная переменная Y:

Y = соотношение покупать (1) или продавать (-1)

Y ((t) = Sign ((Ratio ((t+1) Ratio ((t))

Обратите внимание, что нам не нужно предсказывать цены на реальные торговые показатели, даже не нужно предсказывать реальную стоимость коэффициента (хотя мы можем), нам просто нужно предсказать направление следующего коэффициента.

Шаг 2: Собирать достоверные и точные данные

Изобретатель количественный - ваш друг! Вы просто указываете, какой индекс вы хотите торговать и какой источник данных вы хотите использовать, и он извлекает нужные данные и очищает их для разделения дивидендов и индексов.

Мы получили следующую информацию о торговых днях за последние 10 лет (около 2500 точек данных) с использованием финансовых данных Yahoo: цена открытия, цена закрытия, максимальная цена, минимальная цена и объем торгов.

Третий шаг: разделение данных

Не забывайте об этом очень важном шаге для проверки точности модели. Мы используем следующие данные для обучения/проверки/испытания.

  • Обучение 7 лет ~ 70%

  • Испытание ~ 3 года 30%

ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]

В идеале, мы также должны создавать наборы проверки, но пока мы этого не сделаем.

Четвертый шаг: проектирование характеристик

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

Мы используем следующие функции:

  • 60-дневная скользящая средняя: измерение скользящей средней

  • 5-дневная скользящая средняя: измерение текущего значения среднего

  • 60 дней стандартной погрешности

  • z-соотношение: ((5d MA - 60d MA) / 60d SD

ratios_mavg5 = train.rolling(window=5,
                               center=False).mean()
ratios_mavg60 = train.rolling(window=60,
                               center=False).mean()
std_60 = train.rolling(window=60,
                        center=False).std()
zscore_60_5 = (ratios_mavg5 - ratios_mavg60)/std_60
plt.figure(figsize=(15,7))
plt.plot(train.index, train.values)
plt.plot(ratios_mavg5.index, ratios_mavg5.values)
plt.plot(ratios_mavg60.index, ratios_mavg60.values)
plt.legend(['Ratio','5d Ratio MA', '60d Ratio MA'])
plt.ylabel('Ratio')
plt.show()

img

Соотношение цены 60d и 5d MA

plt.figure(figsize=(15,7))
zscore_60_5.plot()
plt.axhline(0, color='black')
plt.axhline(1.0, color='red', linestyle='--')
plt.axhline(-1.0, color='green', linestyle='--')
plt.legend(['Rolling Ratio z-Score', 'Mean', '+1', '-1'])
plt.show()

img

60-5 Z-показатель соотношения цен

Показатель Z с вращающейся уравнением действительно выводит уравнительную регрессию соотношения!

Шаг 5: Выбор модели

Давайте начнем с очень простой модели. Посмотрим на график z-раздела, и мы увидим, что он возвращается, когда z-раздел слишком высокий или слишком низкий. Давайте будем использовать +1/-1 как наш порог для определения слишком высокого и слишком низкого, а затем мы можем использовать следующую модель для генерации торговых сигналов:

  • Если z меньше -1, то это buy ((1), потому что мы ожидаем, что z вернется к нулю, и поэтому мы увеличиваем его.

  • Когда z больше 1.0, то коэффициент продажи (−1) уменьшается, потому что мы ожидаем, что z вернется к нулю.

Шаг 6: обучение, проверка и оптимизация

И, наконец, давайте посмотрим на реальные эффекты нашей модели на реальные данные.

# Plot the ratios and buy and sell signals from z score
plt.figure(figsize=(15,7))
train[60:].plot()
buy = train.copy()
sell = train.copy()
buy[zscore_60_5>-1] = 0
sell[zscore_60_5<1] = 0
buy[60:].plot(color=’g’, linestyle=’None’, marker=’^’)
sell[60:].plot(color=’r’, linestyle=’None’, marker=’^’)
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,ratios.min(),ratios.max()))
plt.legend([‘Ratio’, ‘Buy Signal’, ‘Sell Signal’])
plt.show()

img

Сигналы ценового соотношения покупки и продажи

Этот сигнал кажется разумным, мы, кажется, продаем коэффициент (красные точки) когда он высокий или увеличивается, и покупаем его обратно, когда он низкий (зеленые точки) и уменьшается. Что это означает для фактических торговых показателей, которые мы торгуем?

# Plot the prices and buy and sell signals from z score
plt.figure(figsize=(18,9))
S1 = data['ADBE'].iloc[:1762]
S2 = data['MSFT'].iloc[:1762]
S1[60:].plot(color='b')
S2[60:].plot(color='c')
buyR = 0*S1.copy()
sellR = 0*S1.copy()
# When buying the ratio, buy S1 and sell S2
buyR[buy!=0] = S1[buy!=0]
sellR[buy!=0] = S2[buy!=0]
# When selling the ratio, sell S1 and buy S2 
buyR[sell!=0] = S2[sell!=0]
sellR[sell!=0] = S1[sell!=0]
buyR[60:].plot(color='g', linestyle='None', marker='^')
sellR[60:].plot(color='r', linestyle='None', marker='^')
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,min(S1.min(),S2.min()),max(S1.max(),S2.max())))
plt.legend(['ADBE','MSFT', 'Buy Signal', 'Sell Signal'])
plt.show()

img

Сигналы для покупки и продажи акций MSFT и ADBE

Обратите внимание на то, как мы иногда зарабатываем на коротких ногах, иногда на длинных ногах, иногда и то, и другое.

Мы были довольны сигналом о тренировочных данных. Давайте посмотрим, какую прибыль может принести этот сигнал. Когда коэффициент низкий, мы можем сделать простой регометр, купить 1 процент (купить 1 ADBE акции и продать коэффициент x MSFT акции), продать 1 процент, когда он высокий (продать 1 ADBE акции и купить коэффициент x MSFT акции) и вычислить PnL сделки по этим коэффициентам.

# Trade using a simple strategy
def trade(S1, S2, window1, window2):
    
    # If window length is 0, algorithm doesn't make sense, so exit
    if (window1 == 0) or (window2 == 0):
        return 0
    
    # Compute rolling mean and rolling standard deviation
    ratios = S1/S2
    ma1 = ratios.rolling(window=window1,
                               center=False).mean()
    ma2 = ratios.rolling(window=window2,
                               center=False).mean()
    std = ratios.rolling(window=window2,
                        center=False).std()
    zscore = (ma1 - ma2)/std
    
    # Simulate trading
    # Start with no money and no positions
    money = 0
    countS1 = 0
    countS2 = 0
    for i in range(len(ratios)):
        # Sell short if the z-score is > 1
        if zscore[i] > 1:
            money += S1[i] - S2[i] * ratios[i]
            countS1 -= 1
            countS2 += ratios[i]
            print('Selling Ratio %s %s %s %s'%(money, ratios[i], countS1,countS2))
        # Buy long if the z-score is < 1
        elif zscore[i] < -1:
            money -= S1[i] - S2[i] * ratios[i]
            countS1 += 1
            countS2 -= ratios[i]
            print('Buying Ratio %s %s %s %s'%(money,ratios[i], countS1,countS2))
        # Clear positions if the z-score between -.5 and .5
        elif abs(zscore[i]) < 0.75:
            money += S1[i] * countS1 + S2[i] * countS2
            countS1 = 0
            countS2 = 0
            print('Exit pos %s %s %s %s'%(money,ratios[i], countS1,countS2))
            
            
    return money
trade(data['ADBE'].iloc[:1763], data['MSFT'].iloc[:1763], 60, 5)

Результат: 1783,375.

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

Мы также можем попробовать более сложные модели, такие как логистическая регрессия, SVM и т. д., чтобы сделать предсказание 1/1.

А теперь давайте продолжим эту модель, и это приведет нас к следующему выводу.

Шаг 7: перепроверка данных теста

Здесь еще упоминается платформа квантования изобретателей, которая использует высокопроизводительный QPS/TPS-рекомендационный двигатель, реально воспроизводит историческую среду, устраняет распространенные ловушки квантования рекомендаций и своевременно обнаруживает недостатки стратегии, что лучше помогает инвестировать в реальные устройства.

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

Это очень просто, и мы можем использовать эту функцию, чтобы посмотреть на PnL в тестовых данных.

trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)

Результат: 5262 868.

Эта модель работает очень хорошо! Она стала нашей первой простой моделью пары сделок.

Избегайте чрезмерного приспособления

Перед тем как закончить обсуждение, я хотел бы особенно обсудить чрезмерную приспособленность. Чрезмерная приспособленность является самой опасной ловушкой в торговых стратегиях.

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

# Find the window length 0-254 
# that gives the highest returns using this strategy
length_scores = [trade(data['ADBE'].iloc[:1762], 
                data['MSFT'].iloc[:1762], l, 5) 
                for l in range(255)]
best_length = np.argmax(length_scores)
print ('Best window length:', best_length)
('Best window length:', 40)

Теперь, когда мы проверяем производительность модели на тестовых данных, мы обнаруживаем, что длина этого окна времени далеко не оптимальна!

# Find the returns for test data
# using what we think is the best window length
length_scores2 = [trade(data['ADBE'].iloc[1762:], 
                  data['MSFT'].iloc[1762:],l,5) 
                  for l in range(255)]
print (best_length, 'day window:', length_scores2[best_length])
# Find the best window length based on this dataset, 
# and the returns using this window length
best_length2 = np.argmax(length_scores2)
print (best_length2, 'day window:', length_scores2[best_length2])
(40, 'day window:', 1252233.1395)
(15, 'day window:', 1449116.4522)

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

plt.figure(figsize=(15,7))
plt.plot(length_scores)
plt.plot(length_scores2)
plt.xlabel('Window length')
plt.ylabel('Score')
plt.legend(['Training', 'Test'])
plt.show()

img

Мы можем видеть, что все, что находится между 20 и 50, является хорошим вариантом для окна времени.

Чтобы избежать чрезмерного приспособления, мы можем использовать природу экономического рассуждения или алгоритмов для выбора длины окна времени. Мы также можем использовать фильтр Кармана, который не требует от нас указания длины; этот метод будет представлен позже в другой статье.

Следующий шаг

В этой статье мы предлагаем несколько простых методов, которые помогут вам продемонстрировать процесс разработки стратегии торговли. На практике, если вы хотите использовать более сложные статистические данные, вы можете рассмотреть следующие варианты:

  • Индекс Херста

  • Период полураспада regression среднего значения, выведенного из процесса Орнштейна-Уленбека

  • Кальманский фильтр


Связанные

Больше

bk_fundНе нашёл этот пакет

bk_fundГде можно установить backtester.dataSource.yahoo_data_source