Далее необходимо создать функции, помогающие алгоритму машинного обучения. В Интернете есть некоторые стандартные функции машинного обучения для финансовых временных рядов, поэтому я последовал их совету.
- В Datacamp есть несколько хороших курсов по машинному обучению, машинному обучению временных рядов и машинному обучению для финансов.
Сначала вычисляется процентное изменение. Я создал четыре новых функции: процентное изменение за 5 и 10 дней в функциях lastTradedVolume и openPrice.bid.
def calc_pct_change(df, features, resolution): #creates 5, 10, pct change based on all features #if resolution is a day, then its n days percent change N = [5, 10] new_features_list = [] for n in N: for feature in features: new_col_name = feature+'_'+ str(n)+'_'+resolution+'_pct_change' df[new_col_name] = df[feature].pct_change(n) new_features_list.append(new_col_name) return(df) resolution = 'Day' features = ['lastTradedVolume', 'openPrice.bid'] prices_df= calc_pct_change(prices_df, features, resolution)
Во-вторых, это расчет индекса относительной силы, который является стандартным расчетом в финансовых кругах. Как и процентное изменение, оно рассчитывается для различных периодов, наиболее распространенными из которых являются 14, 30, 50 и 200. Я применяю это только к функции openPrice.bid.
def create_n_resolution_RSI_change(df, features,resolution): #creates 14, 30, 50, 200 RSI based on all input values AKA only provide the #columns you want to calc RSI for N = [14, 30, 50, 200] new_features_list = [] for n in N: for feature in features: new_col_name = feature+'_'+ str(n)+'_'+resolution+'_RSI' df[new_col_name] = talib.RSI(df[feature].values, timeperiod=n) #new_features_list.append(new_col_name) return(df) prices_df = create_n_resolution_RSI_change(prices_df, ['openPrice.bid'], 'Day')
В-третьих, процентное изменение по сравнению со всем предыдущим временем (отличается от скользящего среднего, рассчитанного выше).
def create_pct_change_2(df): previous_values = df[:-1] last_value = df[-1] percent_change = (last_value - np.mean(previous_values))/np.mean(previous_values) return(percent_change) features = ['lastTradedVolume', 'openPrice.bid'] for feature in features: new_name = feature + '_pct_change_2' prices_df[new_name] = prices_df[feature].rolling(window=20).aggregate(create_pct_change_2)
В-четвертых, удалить выбросы.
def replace_outliers(series): absolute_differences_from_mean = np.abs(series - np.mean(series)) this_mask = absolute_differences_from_mean > (np.std(series)*3) series[this_mask] = np.nanmedian(series) return(series) features = ['lastTradedVolume', 'openPrice.bid', 'lastTradedVolume_5_Day_pct_change', 'openPrice.bid_5_Day_pct_change', 'lastTradedVolume_10_Day_pct_change', 'openPrice.bid_10_Day_pct_change', 'openPrice.bid_14_Day_RSI', 'openPrice.bid_30_Day_RSI', 'openPrice.bid_50_Day_RSI', 'openPrice.bid_200_Day_RSI', 'lastTradedVolume_pct_change_2', 'openPrice.bid_pct_change_2'] for feature in features: new_name = feature + 'no_outliers' prices_df[new_name] = replace_outliers(prices_df[feature])
В-пятых, необходимо создать скользящее стандартное отклонение и скользящее максимальное значение.
def calc_rolling_std_max(df): new_df_std = df.rolling(20).aggregate([np.std]) new_df_max = df.rolling(20).aggregate([np.max]) new_df_std.columns = new_df_std.columns.to_flat_index() new_df_max.columns = new_df_max.columns.to_flat_index() new_df_std = new_df_std.join(new_df_max) return(new_df_std) prices_df = prices_df.join(calc_rolling_std_max(prices_df[['lastTradedVolume', 'openPrice.bid']]))
В-шестых, необходимо создать данные, сдвинутые во времени, чтобы учесть эффекты запаздывания.
def make_time_shift_data(series, feature): shifts = [0, 1, 2, 3, 4, 5, 6, 7 ] many_shifts = {feature+'_lag{}'.format(ii): series.shift(ii) for ii in shifts} many_shifts = pd.DataFrame(many_shifts) return(many_shifts) features = ['lastTradedVolume', 'openPrice.bid'] for feature in features: prices_df = prices_df.join(make_time_shift_data(prices_df[feature], feature))
Вот и все. Выполнена разработка функций.