Untitled
unknown
plain_text
2 years ago
25 kB
7
Indexable
from blueshift.library.pipelines.pipelines import average_volume_filter, technical_factor from blueshift.library.technicals.indicators import rsi, sma, ema, adx, macd from blueshift.pipeline import CustomFactor from blueshift.pipeline.data import EquityPricing import talib as ta from blueshift.pipeline import Pipeline from blueshift.errors import NoFurtherDataError from blueshift.finance import commission, slippage import numpy as np from blueshift.api import (symbol, order, order_target_percent, schedule_function, schedule_once, set_commission, set_slippage, date_rules, time_rules, get_open_positions, get_order, attach_pipeline, pipeline_output, get_datetime, square_off, order_value ) import math from scipy.stats import linregress import pandas as pd import talib as ta import scipy import cvxpy as cp from scipy.optimize import minimize from sklearn.ensemble import RandomForestRegressor from sklearn.linear_model import LinearRegression from sklearn.inspection import permutation_importance from scipy.stats import pearsonr def adx_val(lookback): class ADXFactor(CustomFactor): inputs = [EquityPricing.high, EquityPricing.low, EquityPricing.close] def compute(self, today, assets, out, high, low, close): for idx in range(0, len(assets)): high_arr = high[:, idx] low_arr = low[:, idx] close_arr = close[:, idx] high_arr = high_arr[~np.isnan(high_arr)] low_arr = low_arr[~np.isnan(low_arr)] close_arr = close_arr[~np.isnan(close_arr)] # if idx < 10: # print(high_arr, low_arr, close_arr) try: returns = ta.ADX(high_arr, low_arr, close_arr, timeperiod = 14) out[idx] = returns[-1] except: out[idx] = 0 return ADXFactor(window_length = lookback) def my_volatility(lookback): class SignalVolatility(CustomFactor): inputs = [EquityPricing.close] def compute(self, today, assets, out, close): len_time = close.shape[0] len_assets = close.shape[1] for idx in range(0, len_assets): arr = np.array(close[:, idx]) arr = arr[~np.isnan(arr)] if len(arr) != 0: returns = ta.ROC(arr, 10) returns = returns[~np.isnan(returns)] out[idx] = np.std(returns) else: out[idx] = 0 return SignalVolatility(window_length = lookback) def dev_volume(lookback): class SignalDevVolume(CustomFactor): inputs = [EquityPricing.volume] def compute(self, today, assets, out, volume): historic = volume current = volume[0] mean_val = np.mean(historic, axis = 0) std_dev = np.std(historic, axis = 0) x_val = (current - mean_val) / std_dev out[:] = x_val return SignalDevVolume(window_length = lookback) def avg_volume(lookback): class AvgDailyVolumeTraded(CustomFactor): inputs = [EquityPricing.close, EquityPricing.volume] def compute(self, today, assets, out, close, volume): close = np.nan_to_num(close) volume = np.mean(volume * close, axis=0) out[:] = volume return AvgDailyVolumeTraded(window_length = lookback) def avg_liquidity(lookback): class SignalAverageLiquidity(CustomFactor): inputs = [EquityPricing.high, EquityPricing.low, EquityPricing.close, EquityPricing.volume] def compute(self, today, assets, out, high, low, close, volume): close = np.nan_to_num(close) num = close * volume # den = high - low # den[np.where(den < 0.1)] = 1e9 val = np.mean(np.log(num), axis = 0) out[:] = val return SignalAverageLiquidity(window_length = lookback) def make_screener(context): pipe = Pipeline() # Momentum (RSI) momentum_filter = technical_factor(11, rsi, 10) pipe.add(momentum_filter, 'momentum') # # Exponential Moving Average # ema_filter = technical_factor(15, ema, 10) # pipe.add(ema_filter, 'ema') # Moving Average Convergence Divergence (Not Working) # macd_filter = technical_factor(15, macd, 10) # pipe.add(macd_filter, 'macd') # Simple Moving Average # sma_filter = technical_factor(15, sma, 10) # pipe.add(sma_filter, 'sma') # Average Directional Index (Not Working) # adx_col = my_adx(20) # pipe.add(adx_col, 'adx') # Liquidity liquidity_filter = avg_liquidity(context.params['pipeline_lookback']) pipe.add(liquidity_filter, 'liquidity') # Average Volume volume_filter = avg_volume(context.params['pipeline_lookback']) pipe.add(volume_filter, 'avg_volume') # Recent Deviation in Volume dev_volume_filter = dev_volume(context.params['pipeline_lookback']) pipe.add(dev_volume_filter, 'dev_volume') # Volatility vol_filter = my_volatility(context.params['pipeline_lookback']) pipe.add(vol_filter, 'volatility') # ADX adx_factor = adx_val(context.params['pipeline_lookback']) pipe.add(adx_factor, 'adx') return pipe def rsi_filter(num): if num >= 70: return 1 elif num >= 30: return 0 else: return -1 def screener(context, data): try: pipeline_results = pipeline_output('my_screener') except: print('no pipeline for {}'.format(get_datetime())) return [] pipeline_results.replace([np.inf, -np.inf], 0, inplace=True) pipeline_results.fillna(0, inplace=True) pipeline_results['momentum'] = pipeline_results['momentum'].apply(rsi_filter) print(pipeline_results) return pipeline_results def optimise_portfolio(context, data): price = context.signals = dict((security, None) for security in context.securities) for security in context.securities: price[security] = data.history(security, ['open', 'high', 'low', 'close'], 252, '1d') stocks = pd.DataFrame() stocks.index = list(price[context.securities[0]].index) for security in context.securities: stocks[str(security.name)] = price[security]['close'] log_return = np.log(stocks/stocks.shift(1)) numAssets = len(context.securities) def get_ret_vol_sr(weights): weights = np.array(weights) ret = np.sum(log_return.mean() * weights) * context.params['lookback'] vol = np.sqrt(np.dot(weights.T,np.dot(log_return.cov()*context.params['lookback'],weights))) sr = ret/vol return np.array([ret,vol,sr]) def neg_sharpe(weights): return get_ret_vol_sr(weights)[2] * -1 cons = ({'type':'eq', 'fun': lambda x : np.sum(x) - 1}) bound = (0, 1) bounds = list(bound for asset in range(numAssets)) opt_results = minimize(neg_sharpe, numAssets * [1./ numAssets], method='SLSQP', bounds=bounds, constraints=cons) for i, key in enumerate(context.weights.keys()): context.weights[key] = opt_results.x[i] def randForestRegressorNew(df): df_new = df.fillna(0) df_new = df_new.replace([np.inf, -np.inf], 0) x = df_new.columns[:-1] y = df_new.columns[-1] # print(x,y) # print(df_new[x], df_new[y]) forest = LinearRegression() forest.fit(df_new[x], df_new[y]) print('fit success') # result = permutation_importance(forest, df_new[x], df_new[y], n_repeats=10, random_state=42, n_jobs=2) return forest # result['importances_mean']/np.sum(result['importances_mean']) def compute_correlation(asset,context,data): offset = context.params['correlation_offset'] window = context.params['correlation_window'] + 1 benchmark_df = data.history(symbol('NIFTY'),['open','close'],360*window,'1m') cnt = 1 corr = [] stock_df = data.history(asset, ["open", "close"], 360*window , "1m") benchmark = [] stock = [] cnt = 0 for i in range(360*window): if(cnt+offset+60 >= len(benchmark_df["close"]) or cnt+60 >= len(stock_df["close"])): break # while cnt < (360*window - offset - 60): benchmark.append((benchmark_df["open"][cnt+offset] + benchmark_df["close"][cnt + offset + 60]) / 2) stock.append((stock_df["open"][cnt] + stock_df["close"][cnt + 60]) / 2) cnt += 60 if(len(benchmark)==0): print('benchmark len error') # print(asset) # print(pearsonr(benchmark, stock)) coefficient, _ = pearsonr(benchmark, stock) # print(asset) return coefficient def random_forest_filter(context, data): print('here') if(context.ml_params_init==False): print('None detected') pipeline_results = screener(context, data) pipeline_results = pipeline_results.sort_values('adx')[-100:] stock_list = pipeline_results.index # print(stock_list) corr_col = [] for sec in stock_list: try: corr_col.append(compute_correlation(sec,context,data)) except: corr_col.append(0) context.open_price[sec] = data.current(sec,'close') # print(corr_col) pipeline_results["Correlation"] = corr_col context.ml_params = pipeline_results context.ml_params_init = True # for sec in stock_list: # # print(data.current(sec,'open')) # if(math.isnan(data.current(sec,'close'))): # print('error:', sec) # context.open_price[sec] = data.current(sec,'close')#data.history(sec,'open',1,'1m')[0] # context.ml_params.loc[sec]['sma'] = context.ml_params.loc[sec]['sma'] / context.open_price[sec] # context.ml_params.loc[sec]['ema'] = context.ml_params.loc[sec]['ema'] / context.open_price[sec] return [symbol('TCS'), symbol('ITC'), symbol('INFY'), symbol('HDFCBANK'), symbol('HINDUNILVR')] print('here') df = context.ml_params stock_list = df.index # print(stock_list) results = [] for sec in stock_list: try: data_close = data.current(sec,'close') #data.history(sec,'close',1,'1m')[0] # print(data_close) # if(len(data_close)!=0): results.append((data_close - context.open_price[sec])/data_close) # else: # results.append(0) except: data_close = data.current(sec, 'close') print(data_close) # print(data_close,data.history(sec,'close',1,'1m')[0]) results.append(0) context.open_price[sec] = 100000 print('error in computing results',sec) print('here') df["Results"] = results #todo: scale the parameters print('waiting for forest') forest = randForestRegressorNew(df) print('got forest') pipeline_results = screener(context, data) pipeline_results = pipeline_results.sort_values('adx')[-100:] # pipeline_results = pipeline_results.fillna(0) stock_list = pipeline_results.index #todo: update security list corr_col = [] new_values = [] print('got pipeline') for sec in stock_list: # print(sec) # print(sec, pipeline_results.loc[sec]) try: context.open_price[sec] = data.current(sec,'close') pipeline_row = list(pipeline_results.loc[sec]) corr = compute_correlation(sec,context,data) pipeline_row.append(corr) corr_col.append(corr) new_values.append([forest.predict([pipeline_row]), sec]) except: print('error in compute correlation',sec) corr = 0 corr_col.append(corr) print('prediction successful') pipeline_results["Correlation"] = corr_col context.ml_params = pipeline_results print('parameter update success') new_values.sort(reverse = True) print(new_values) top_assets = [] len_stocks = len(new_values) // 10 for i, x in enumerate(new_values): top_assets.append(x[1]) if i > len_stocks: break print('asset extracted') return top_assets def find_stocks_forest(context, data): try: context.securities = random_forest_filter(context,data) except Exception as e: print('error in random forest',e) context.securities = [symbol('TCS'), symbol('ITC'), symbol('INFY'), symbol('HDFCBANK'), symbol('HINDUNILVR')] print(context.securities) context.signals = dict((security, 0) for security in context.securities) context.target_position = dict((security, [0, 0]) for security in context.securities) context.set_flag = dict((security, 0) for security in context.securities) context.counter = dict((security, 0) for security in context.securities) context.weights = dict((security, 1 / len(context.securities)) for security in context.securities) context.trade = True if(context.params['Optimizer_status']): optimise_portfolio(context, data) print(context.weights) def ohlc4(security, context, data): price = data.history(security, ['open', 'high', 'low', 'close'], context.params['lookback'], context.params['indicator_freq']).iloc[::-1] # print(price["close"][0]) price['ohlc4'] = (price['open'] + price['high'] + price['low'] + price['close'])/4 price.reset_index(inplace=True) price = price.rename(columns={'index': 'timestamp'}) return price def get_channel(price, n): reg = list(range(1, n)) mid = np.mean(price[0:n]) slope = linregress(reg, price[:-1]).slope - linregress(reg, price[1:]).slope intercept = mid - slope * (n / 2) + (1 - n % 2) * slope / 2 endy = intercept + slope * (n - 1) dev = 0.0 for x in range(0, n): dev += math.pow(price[x] - (intercept + slope * (n - x)), 2) dev = math.sqrt(dev / n) return intercept, endy, dev, slope def rising(price, n): return all(i < j for i, j in zip(price[:n], price[1:n + 1])) def falling(price, n): return all(i > j for i, j in zip(price[:n], price[1:n + 1])) def standard_deviation(price, len): mid = price[0:len].mean() dev = 0.0 for x in range(0, len): dev += math.pow(price[x] - mid, 2) dev = math.sqrt(dev / (len - 1)) return dev def initialize(context): context.params = { 'pipeline_lookback':30, 'lookback': 30, 'indicator_freq': '30m', 'buy_signal_threshold': 0.5, 'sell_signal_threshold': -0.5, 'SMA_period_short': 15, 'SMA_period_long': 60, 'RSI_period': 60, 'trade_freq': 60, 'leverage': 1, 'i_deviation': 2, 'BBands_period': 14, 'Pipeline_status': False, 'Optimizer_status': False, 'correlation_offset':60, 'correlation_window':1, 'num_ml_params':4, 'max_orders': 3} schedule_function(find_stocks_forest, date_rule=date_rules.month_start(0),time_rule = time_rules.on_open()) attach_pipeline(make_screener(context), name='my_screener') context.securities = [symbol('UNIONBANK'), symbol('EASEMYTRIP'), symbol('LSIL'), symbol('FEDERALBNK'), symbol('HINDCOPPER')] set_commission(commission.PerShare(cost=0.0, min_trade_cost=0.0)) set_slippage(slippage.FixedSlippage(0.00)) context.signals = dict((security, 0) for security in context.securities) context.target_position = dict((security, [0, 0]) for security in context.securities) context.set_flag = dict((security, 0) for security in context.securities) context.counter = dict((security, 0) for security in context.securities) context.weights = dict((security, 1 / len(context.securities)) for security in context.securities) context.ml_params = None context.ml_params_init = False # for i in range(context.params['num_ml_params']): # context.ml_params[i] = [0]*len(context.securities) # context.results = [0]*len(context.securities) context.open_price = dict() schedule_function(run_strategy, date_rule=date_rules.every_day(), time_rule=time_rules.every_nth_minute(context.params['trade_freq'])) schedule_function(square, date_rules.every_day(), time_rules.market_close(minutes=15)) schedule_function(stop_trading, date_rules.month_end(), time_rules.market_close(minutes=15)) context.trade = False context.take_profit = None context.stop_loss = None def square(context,data): square_off() context.counter = dict((security, 0) for security in context.securities) def square_off_positions(context,data): # square_off() context.trade = False # data_h = data.history(symbol('TCS'),['open','close','volume','high','low'],1,'1m') # data_h.reset_index(inplace=True) # data_h = data_h.rename(columns = {'index':'timestamp'}) # print("Squaring off at ", data_h['timestamp']) # def before_trading_start(context, data): # context.trade = True def stop_trading(context, data): context.trade = False def run_strategy(context, data): if context.trade == False: return for security in context.securities: try: price = ohlc4(security, context, data) except: print("Price Error") return pos = get_open_positions() curr_price = data.current(security,'close') if context.set_flag[security] == -1 and len(price['close'])!=0: context.target_position[security] = [abs(price['close'][0] - price['open'][0]), price['low'][0]] context.set_flag[security] = 0 # print(context.target_position[security], pos[security].buy_price) try: trade = signal_function(security, price, context, data) except: trade = 0 if trade == 1: remain_capital = context.account.available_funds curr_price = data.current(security,'close') order_val = int(remain_capital*context.weights[security]) # print(security, trade) order_id = order_value(security, 5 * order_val) context.set_flag[security] = -1 if(order_id!=None): context.counter[security] = context.counter[security]+1 # print(security) # order_id = order_target_percent(security, 100 * context.weights[security]) elif trade == -1: order_id = order_target_percent(security, 0) if(order_id!=None): context.counter[security] = 0 def signal_function(security, price, context, data): #y_low, y_high, dev, slope = get_channel(price['ohlc4'], context.params['lookback']) std_dev = standard_deviation(price['ohlc4'], context.params['lookback']) # print(y_low, y_high, dev, slope, std_dev) long_c1 = rising(price['ohlc4'], 2) #long_n = price['close'][4] < price['open'][4] and price['close'][3] < price['open'][3] and price['close'][2] < price['open'][2] and price['close'][1] < price['open'][1] and (abs(price['close'][1] - price['open'][1]) > abs(price['close'][2] - price['open'][2])) and (abs(price['close'][2] - price['open'][2]) > abs(price['close'][3] - price['open'][3])) and (abs(price['close'][3] - price['open'][3]) > abs(price['close'][4] - price['open'][4])) # print(long_c1) # avg = ta.SMA(price['close'].values, 20) #print("Sma", avg) long_c2 = (price['ohlc4'][0] > price['ohlc4'][1] + std_dev / 2) long_c3 = price['high'][1] <= price['close'][0] long_condition = (long_c1 or long_c2) and long_c3 #or rising(avg[-4:], 3))) exit_c1 = falling(price['ohlc4'], 2) exit_c2 = (price['ohlc4'][0] < price['ohlc4'][1] - std_dev / 2) exit_c3 = (price['low'][1] >= price['close'][0]) # #exit_n = price['close'][4] > price['open'][4] and price['close'][3] > price['open'][3] and price['close'][2] > price['open'][2] and price['close'][1] > price['open'][1] and (abs(price['close'][1] - price['open'][1]) > abs(price['close'][2] - price['open'][2])) and (abs(price['close'][2] - price['open'][2]) > abs(price['close'][3] - price['open'][3])) and (abs(price['close'][3] - price['open'][3]) > abs(price['close'][4] - price['open'][4])) # exit_condition = exit_c1 #or exit_c2) and exit_c3 #or falling(avg[-4:], 3))) exit_condition = exit_c1 # print(long_condition, exit_condition) open_positions = get_open_positions() present = (security in open_positions) curr_price = data.current(security, 'close') # print(long_c1, exit_c1) if long_condition and (not present or open_positions[security].quantity == 0): return 1 # if present and open_positions[security].quantity > 0: # if exit_condition: # return -1 # if curr_price < 0.99 * open_positions[security].buy_price: # return -1 return 0 # def extract_stock_random_forest_weights(context,data): # data_p = context.ml_params # results = [] # idx = 0 # for(sec in context.securities): # data_close = data.history(sec,'close',1,'1m') # results.append((data_close[0] - context.open_price[idx])/data_close[0]) # idx = idx +1 # data_p.append(results) # #todo: scale the parameters # df = pd.DataFrame(data_p) # weights = randForestRegressorNew(df) # return weights # def sort_random_forest(context,data,weights): # pipeline_results = pipeline_output('my_screener') # #todo: update security list # new_values = [] # sorted_asset = [] # for(sec in context.securities): # new_values.append([compute_correlation(sec,context,data)*weights[0]+ # pipeline_results['momentum'][sec]*weights[1]+ # pipeline_results['liquidity'][sec]*weights[2]+ # pipeline_results['avg_volume'][sec]*weights[3],sec]) # new_values.sort() # for x in new_values: # sorted_asset.append(x[1]) # return sorted_asset # def update_random_forest_param(context,data): # ml_params = [[],[],[],[]] # context.open_price = [] # pipeline_results = pipeline_output('my_screener') # for sec in context.securities: # data_open = data.history(sec,'open',1,'1m') # ml_params[0].append(compute_correlation(sec,context,data)) # ml_params[1].append(pipeline_results['momentum'][sec]) # ml_params[2].append(pipeline_results['liquidity'][sec]) # ml_params[3].append(pipeline_results['avg_volume'][sec]) # context.open_price.append(data_open[0]) # context.ml_params = ml_params # def find_stocks(context, data): # data_h = data.history(symbol('TCS'),['open','close','volume','high','low'],1,'1m') # data_h.reset_index(inplace=True) # data_h = data_h.rename(columns = {'index':'timestamp'}) # if(context.params['Pipeline_status']): # context.securities = screener(context, data) # else: # context.securities = [symbol('TCS'), symbol('ITC'), symbol('INFY'), symbol('HDFCBANK'), symbol('HINDUNILVR')] # # print(screener(context, data)) # context.trade = True # open_positions = get_open_positions() # # print(data_h['timestamp']) # for asset in open_positions: # print('open_position_detected',asset) # context.signals = dict((security, 0) for security in context.securities) # context.target_position = dict((security, [0, 0]) for security in context.securities) # context.set_flag = dict((security, 0) for security in context.securities) # context.weights = dict((security, 1 / len(context.securities)) for security in context.securities) # # context.buy_price = dict((security, 0) for security in context.securities) # # context.profit = dict((security, 0) for security in context.securities) # if(context.params['Optimizer_status']): # optimise_portfolio(context, data) # print(context.weights)
Editor is loading...