def _handle_data(context, data): s1 = context.asset prices = data.history(s1, bar_count=context.BARS, fields=['price', 'open', 'high', 'low', 'close'], frequency=context.frequency) analysis = pd.DataFrame(index=prices.index) # SMA FAST analysis['sma_f'] = ta.SMA(prices.close.as_matrix(), context.SMA_FAST) # SMA SLOW analysis['sma_s'] = ta.SMA(prices.close.as_matrix(), context.SMA_SLOW) # SMA FAST over SLOW Crossover analysis['sma_test'] = np.where(analysis.sma_f > analysis.sma_s, 1, 0) # Save the prices and analysis to send to analyze context.prices = prices context.analysis = analysis context.price = data.current(context.asset, 'price') record(price=data.current(context.asset, 'price'), cash=context.portfolio.cash, short_mavg=analysis['sma_f'], long_mavg=analysis['sma_s']) makeOrders(context, analysis)
def _set_current_fields(self, context, data): try: # In live mode, "volume", "close" and "price" are the only available fields. # In live mode, "volume" returns the last 24 hour trading volume. # Update actual self.state.price if not self.is_backtest: self.state.current = data.current( assets=self.state.asset, fields=["volume", "close", "price"] ) else: self.state.current = data.current( assets=self.state.asset, fields=["open", "high", "low", "volume", "close", "price"], ) self.state.price = self.state.current.price record( price=self.state.price, cash=context.portfolio.cash, volume=self.state.current.volume, ) self.state.dump_to_context(context) return True except exchange_errors.NoValueForField as e: self.log.warning(e) self.log.warning(f"Skipping trade period: {e}") return False except KeyError: self.log.warning("Error when getting current fields") return False
def handle_data(context, data): last3 = [] last3orig = data.history(context.asset, 'price', bar_count=3, frequency='1T') last3[:] = last3orig if context.portfolio.positions[context.asset].amount == 0: if sorted(last3) == last3: print("here") cash = context.portfolio.cash context.cur_price = data.current(context.asset, 'price') buy_amount = int( min(cash // context.cur_price, 100000 // context.cur_price)) order(context.asset, buy_amount) else: if data.current(context.asset, 'price') < .9 * context.cur_price: num = context.portfolio.positions[context.asset].amount order(context.asset, -num) if sorted(last3) != last3 and (context.cur_price * 1.15) < data.current( context.asset, 'price'): print("HERE") num = context.portfolio.positions[context.asset].amount order(context.asset, -num) record(btc=data.current(context.asset, 'price'))
def trade(self, context, data): """ This is the brain of the agent and it is what carries out trades """ # Get current price price = data.current(self.market, 'price') # Check if price is ok if price is np.nan: self.logger.warn('No pricing data') return record(price=price) # Activate possible stop losses # if self.order(self.stop_loss, context, data): # return # Check current orders for this market # if len(get_open_orders(self.market)) > 0: # self.logger.info('Skipping frame until all open orders execute') # return # if not data.can_trade(self.market): # self.logger.warn("Can't trade!") # return # Call strategy self.order(self.strategy, context, data)
def _handle_data(context, data): s1 = context.asset prices = data.history( s1, bar_count=context.BARS, fields=["price", "open", "high", "low", "price"], frequency=context.frequency, ) analysis = pd.DataFrame(index=prices.index) # SMA FAST analysis["sma_f"] = ta.SMA(prices.close.as_matrix(), context.SMA_FAST) # SMA SLOW analysis["sma_s"] = ta.SMA(prices.close.as_matrix(), context.SMA_SLOW) # SMA FAST over SLOW Crossover analysis["sma_test"] = np.where(analysis.sma_f > analysis.sma_s, 1, 0) # Save the prices and analysis to send to analyze context.prices = prices context.analysis = analysis context.price = data.current(context.asset, "price") record( price=data.current(context.asset, "price"), cash=context.portfolio.cash, short_mavg=analysis["sma_f"], long_mavg=analysis["sma_s"], ) makeOrders(context, analysis)
def record_data(self, context): """Records external data for the current algo iteration Data from the external dataset is recorded to Catalyst's persistant context object along with market data Arguments: context {pd.Dataframe} -- Catalyst peristent algo context object Returns: dict -- Dict of column keys and data recored to catalyst """ date = context.blotter.current_dt.date() record_payload = {} if date not in self.df.index: raise ValueError("No {} data found for {}".format(self.name, date)) for k in self.columns: current_val = self.column_by_date(k, date) # TODO: some dates are doubled due to smaller date steps if isinstance(current_val, pd.Series): current_val = current_val.mean() record_payload[k] = current_val self.log.debug("Recording {}".format(record_payload)) record(**record_payload) return record_payload
def handle_data(context, data): look_back_window = 20 # Skip bars until we can calculate absolute momentum context.i += 1 if context.i < look_back_window: return btc_history = data.history(context.asset, 'price', bar_count=look_back_window, frequency='1D') percentage_change = btc_history.pct_change(look_back_window - 1)[-1] * 100 price = data.current(context.asset, 'price') # Trading logic # Buy if the percentage change > 0 if percentage_change > 0: if not context.holding: order_target_percent(context.asset, 1) context.holding = True # Sell otherwise else: if context.holding: order_target_percent(context.asset, 0) context.holding = False record(price=price, cash=context.portfolio.cash, percent_change=percentage_change)
def handle_data(context, data): log.info('handling bar: {}'.format(data.current_dt)) price = data.current(context.asset, 'close') log.info('got price {price}'.format(price=price)) prices = data.history( context.asset, fields='price', bar_count=20, frequency='30T' ) last_traded = prices.index[-1] log.info('last candle date: {}'.format(last_traded)) rsi = talib.RSI(prices.values, timeperiod=14)[-1] log.info('got rsi: {}'.format(rsi)) # If base_price is not set, we use the current value. This is the # price at the first bar which we reference to calculate price_change. if context.base_price is None: context.base_price = price price_change = (price - context.base_price) / context.base_price cash = context.portfolio.cash # Now that we've collected all current data for this frame, we use # the record() method to save it. This data will be available as # a parameter of the analyze() function for further analysis. record( price=price, price_change=price_change, cash=cash )
def run(self): ts = self.context.cmx_signal.ts if ts is None: return if self._last_update_ts is None or ts - self._last_update_ts >= self.refresh_tdelta: record( cmx_signal=self.context.cmx_signal.signal, cmx_signal_mean=self.context.cmx_signal.mean, cmx_signal_std=self.context.cmx_signal.std, cmx_signal_zscore=self.context.cmx_signal.zscore, cmx_pnl=self.context.cmx_risk.pnl, cmx_position=self.context.cmx_invent.positions[0], cmx_amount=self.context.cmx_invent.amounts[0], cmx_prices=self.context.cmx_invent.prices.copy(), cmx_low_prices=self.context.cmx_invent.lower_prices.copy(), cmx_high_prices=self.context.cmx_invent.upper_prices.copy(), cmx_pnls=self.context.cmx_risk.leg_pnls.copy(), cmx_positions=self.context.cmx_invent.positions.copy(), cmx_amounts=self.context.cmx_invent.amounts.copy(), cmx_traded=self.context.cmx_invent.trade_positions.copy(), cmx_unhedged_amounts=self.context.cmx_invent.unhedged_amounts. copy(), cmx_unhedged_positions=self.context.cmx_invent. unhedged_positions.copy(), ) self._last_update_ts = ts
def handle_data(context, data): # Skip bars until we can calculate momentum context.i += 1 if context.i < context.look_back_window: return btc_price = data.current(context.btc.asset_usdt, 'price') if context.i % context.look_back_window == 0: highest_momentum_value = 0 highest_momentum_asset = None for asset in context.assets: asset_momentum = asset.get_momentum(data) if asset_momentum > highest_momentum_value: highest_momentum_asset = asset highest_momentum_value = asset_momentum if highest_momentum_value > 0: print("buying {}, with momentum of {} at {}".format( highest_momentum_asset.name, highest_momentum_value, data.current_dt)) for asset in context.assets: if asset.name != highest_momentum_asset.name: asset.sell_all() highest_momentum_asset.buy_all() else: print("Bear market sell all at {}".format(data.current_dt)) for asset in context.assets: asset.sell_all() record(btc_price=btc_price, cash=context.portfolio.cash)
def handle_data(context, data): print('handling bar: {}'.format(data.current_dt)) price = data.current(context.asset, 'close') print('got price {price}'.format(price=price)) try: prices = data.history( context.asset, fields='price', bar_count=14, frequency='15T' ) rsi = talib.RSI(prices.values, timeperiod=14)[-1] print('got rsi: {}'.format(rsi)) except Exception as e: print(e) # If base_price is not set, we use the current value. This is the # price at the first bar which we reference to calculate price_change. if context.base_price is None: context.base_price = price price_change = (price - context.base_price) / context.base_price cash = context.portfolio.cash # Now that we've collected all current data for this frame, we use # the record() method to save it. This data will be available as # a parameter of the analyze() function for further analysis. record( price=price, price_change=price_change, cash=cash )
def handle_data(context, data): RSI_periods = 14 context.i += 1 if context.i < RSI_periods: return RSI_data = data.history(context.asset, "price", bar_count=RSI_periods, frequency="30T") # compute RSI oversold = 30 overbought = 70 deltas = RSI_data.diff() seed = deltas[:RSI_periods + 1] up = seed[seed >= 0].sum() / RSI_periods down = -seed[seed < 0].sum() / RSI_periods RS = up / down RSI = 100 - (100 / (1 + RS)) # get current price price = data.current(context.asset, "price") if context.base_price == None: context.base_price = price price_change = (price - context.base_price) / context.base_price record(price=price, cash=context.portfolio.cash, price_change=price_change, RSI=RSI) orders = context.blotter.open_orders if len(orders) > 0: return if not data.can_trade(context.asset): print("Cannot trade right now") return pos_amount = context.portfolio.positions[context.asset].amount # strategy logic if pos_amount == 0 and RSI <= oversold: order_target_percent(context.asset, 1) elif pos_amount < 0 and RSI <= 40: order_target_percent(context.asset, 0) elif pos_amount == 0 and RSI >= overbought: order_target_percent(context.asset, -1) elif pos_amount > 0 and RSI >= 60: order_target_percent(context.asset, 0)
def handle_data(context, data): context.i += 1 high_history = data.history(context.asset, 'high', bar_count=3, frequency="1D") low_history = data.history(context.asset, 'low', bar_count=3, frequency="1D") open = data.current(context.asset, 'open') high = data.current(context.asset, 'high') low = data.current(context.asset, 'low') close = data.current(context.asset, 'close') volume = data.current(context.asset, 'volume') price = data.current(context.asset, 'price') signal = inside_bar_signal(high_history, low_history) if signal == 1: # Bull break print("Bull break") order_target_percent(context.asset, 1) elif signal == -1: # Bear break print("Bear break") order_target_percent(context.asset, 0) record(open=open, high=high, low=low, close=close, volume=volume, price=price, signal=signal)
def handle_data(context, data): cash = context.portfolio.cash target_hodl_value = TARGET_HODL_RATIO * context.portfolio.starting_cash reserve_value = RESERVE_RATIO * context.portfolio.starting_cash # Cancel any outstanding orders orders = get_open_orders(context.asset) or [] for order in orders: cancel_order(order) # Stop buying after passing the reserve threshold if cash <= reserve_value: context.is_buying = False # Retrieve current asset price from pricing data price = data[context.asset].price # Check if still buying and could (approximately) afford another purchase if context.is_buying and cash > price: # Place order to make position in asset equal to target_hodl_value order_target_value( context.asset, target_hodl_value, limit_price=price * 1.1, stop_price=price * 0.9, ) record( price=price, cash=cash, starting_cash=context.portfolio.starting_cash, leverage=context.account.leverage, )
def handle_data(context, data): price = data.current(context.asset, 'price') prices = data.history( context.asset, bar_count=context.lookback_period, fields=['price', 'open', 'high', 'low', 'close'], frequency='1d' ) macd, macd_signal, macd_hist = ta.MACD( prices['close'].values, fastperiod=12, slowperiod=26, signalperiod=9 ) macd_current = macd[-1] macd_signal_current = macd_signal[-1] macd_prev = macd[-2] macd_signal_prev = macd_signal[-2] # Record MACD record( price=price, cash=context.portfolio.cash, macd=macd[-1], macd_signal=macd_signal[-1], macd_hist=macd_hist[-1] ) # Check we dont have any open orders #orders = context.blotter.open_orders # if len(orders) > 0: # Manage existing trades # return # Exit if we cannot trade if not data.can_trade(context.asset): return # Buy / sell signals if macd_prev < macd_signal_prev and macd_current > macd_signal_current: print("Buy opportunity") # Buy if not context.bought: print("BUYING") order_target_percent(context.asset, 1) context.bought = True elif macd_prev > macd_signal_prev and macd_current < macd_signal_current: # Sell print("Sell opportunity") # Buy if context.bought: print("EXITING POSITION") order_target_percent(context.asset, 0) context.bought = False
def handle_data(context, data): context.day_timer += 1 if LIVE: log.info(f" Current day timer: {context.day_timer} ") # 4hour Momstop if context.buy_all: trigger_buy_holdings(context, data) context.buy_all = False if context.liquidate_all: trigger_liquidate_holdings(context, data) context.liquidate_all = False if context.day_timer % context.trading_execution_time == 0: log_portfolio(context, NAMESPACE) for asset in context.assets[1:]: # ------History / Indicator logic------ # load_history_and_indicators(context, data, asset) # ------ History / Indicator logic------ # # ------ Order logic ------ # log.info( f"4 Hour Momstop: Asset: {asset.symbol.asset_name} Price: {asset.price} VSTOP: {asset.vstop}" ) # Specific assets triggers: trigger_vstop_trend_change(context, data, asset) # ------ Order logic ------ # record(cash=context.portfolio.cash) if asset == context.assets[1]: record(price_1=asset.price, vstop_1=asset.vstop) if asset == context.assets[2]: record(price_2=asset.price, vstop_2=asset.vstop) if context.day_timer >= context.btc_trading_execution_time: asset = context.assets[0] # ------History / Indicator logic------ # load_history_and_indicators(context, data, asset) # ------ History / Indicator logic------ # # ------ Order logic ------ # log.info( f"Asset: {asset.symbol.asset_name} Price: {asset.price} VSTOP: {asset.vstop}" ) # Portfolio triggers: # Specific assets triggers: trigger_btc_rsi_dip(context, data, asset) trigger_vstop_trend_change(context, data, asset) # ------ Order logic ------ # # ------ Record Graph variables ------# if not LIVE: record(cash=context.portfolio.cash) record(price_0=asset.price, vstop_0=asset.vstop, rsi=asset.rsi) context.day_timer = 1
def rebalance(context, data): context.i += 1 # skip first LONG_WINDOW bars to fill windows if context.i < LONG_WINDOW: return # get pipeline data for asset of interest pipeline_data = context.pipeline_data pipeline_data = pipeline_data[pipeline_data.index == context.asset].iloc[0] # retrieve long and short moving averages from pipeline short_mavg = pipeline_data.short_mavg long_mavg = pipeline_data.long_mavg price = pipeline_data.price # check that order has not already been placed open_orders = get_open_orders() if context.asset not in open_orders: # check that the asset of interest can currently be traded if data.can_trade(context.asset): # adjust portfolio based on comparison of long and short vwap if short_mavg > long_mavg: order_target_percent(context.asset, TARGET_INVESTMENT_RATIO) elif short_mavg < long_mavg: order_target_percent(context.asset, 0.0) record( price=price, cash=context.portfolio.cash, leverage=context.account.leverage, short_mavg=short_mavg, long_mavg=long_mavg, )
def handle_data(context, data): # define the windows for the moving averages short_window = 50 long_window = 200 # Skip as many bars as long_window to properly compute the average context.i += 1 if context.i < long_window: return # Compute moving averages calling data.history() for each # moving average with the appropriate parameters. We choose to use # minute bars for this simulation -> freq="1m" # Returns a pandas dataframe. short_mavg = data.history(context.asset, 'price', bar_count=short_window, frequency="1m").mean() long_mavg = data.history(context.asset, 'price', bar_count=long_window, frequency="1m").mean() # Let's keep the price of our asset in a more handy variable price = data.current(context.asset, 'price') # If base_price is not set, we use the current value. This is the # price at the first bar which we reference to calculate price_change. if context.base_price is None: context.base_price = price price_change = (price - context.base_price) / context.base_price # Save values for later inspection record(price=price, cash=context.portfolio.cash, price_change=price_change, short_mavg=short_mavg, long_mavg=long_mavg) # Since we are using limit orders, some orders may not execute immediately # we wait until all orders are executed before considering more trades. orders = get_open_orders(context.asset) if len(orders) > 0: return # Exit if we cannot trade if not data.can_trade(context.asset): return # We check what's our position on our portfolio and trade accordingly pos_amount = context.portfolio.positions[context.asset].amount # Trading logic if short_mavg > long_mavg and pos_amount == 0: # we buy 100% of our portfolio for this asset order_target_percent(context.asset, 1) elif short_mavg < long_mavg and pos_amount > 0: # we sell all our positions for this asset order_target_percent(context.asset, 0)
def handle_data(context, data): """ 在每个交易周期上运行的策略 """ context.i += 1 # 记录交易周期 if context.i < RSI_PERIODS + 3: # 如果交易周期过短,无法计算RSI,则跳过循环 return # 获得历史价格 hitory_data = data.history( context.asset, 'close', bar_count=RSI_PERIODS + 3, frequency='1D', ) # 获取当前持仓数量 pos_amount = round(context.portfolio.positions[context.asset].amount, 1) # 计算RSI rsi_vals = talib.RSI(hitory_data, timeperiod=RSI_PERIODS) # RSI 交易策略 if (rsi_vals[-3] <= RSI_OVER_SOLD_THRESH) and ( rsi_vals[-2] >= RSI_OVER_SOLD_THRESH) and pos_amount == 0: # RSI值上穿超卖阈值,买入 order_target_percent(context.asset, 1) context.signal = SIGNAL_BUY if (rsi_vals[-3] >= RSI_OVER_BOUGHT_THRESH) and ( rsi_vals[-2] <= RSI_OVER_BOUGHT_THRESH) and pos_amount > 0: # RSI值下穿超卖阈值,卖出 order_target_percent(context.asset, 0) context.signal = SIGNAL_SELL # 获取当前的价格 price = data.current(context.asset, 'price') if context.base_price is None: # 如果没有设置初始价格,将第一个周期的价格作为初始价格 context.base_price = price # 计算价格变化百分比,作为基准 price_change = (price - context.base_price) / context.base_price # 记录每个交易周期的信息 # 1. 价格, 2. 现金, 3. 价格变化率, 4. 快线均值, 5. 慢线均值 record(price=price, cash=context.portfolio.cash, price_change=price_change, rsi=rsi_vals[-1], signal=context.signal) # 输出信息 print('日期:{},价格:{:.4f},资产:{:.2f},持仓量:{:.8f}, {}'.format( data.current_dt, price, context.portfolio.portfolio_value, pos_amount, context.signal)) # 进行下一次交易前重置交易信号 context.signal = SIGNAL_INIT
def record(self): """Records indicator's output to catalyst results""" payload = {} for out in self.outputs.columns: val = self.outputs[out].iloc[-1] payload[out] = val self.log.debug(payload) record(**payload)
def handle_data(context, data): """ 循环运行策略 """ # 每个交易周期买入1个比特币 order(context.asset, 1) # 记录每个交易周期的比特币价格 record(btc=data.current(context.asset, 'price'))
def rebalance(context, data): context.i += 1 # Skip first LONG_WINDOW bars to fill windows if context.i < context.WIN DOW: return # Get pipeline data for asset of interest pipeline_data = context.pipeline_data pipeline_data = pipeline_data[pipeline_data.index == context.asset].iloc[0] # Compute the necessary statistics sma = pipeline_data.sma std = pipeline_data.std() price = pipeline_data.price # Compute buy and sell thresholds # Buy threshold is the simple moving average value plus one standard dev. # Sell threshold is the simple moving average value minus one standard dev. buy_threshold = sma-0.3*std/math.sqrt(context.WINDOW) sell_threshold = sma+0.3*std/math.sqrt(context.WINDOW) # Check that the order has not already been placed open_orders = get_open_orders() if context.asset not in open_orders: # check that the asset of interest can currently be traded if data.can_trade(context.asset): # Trading logic: if price is less than the buy threshold, mean # reversion should drive price up. Algorithm invests 100% in the # asset. In the opposite case, mean reversion should drive price # down. Algorithm invests 50% in cash and 50% in the asset. If # price is between buy and sell thresholds, algorithm invests 25% # in cash and 75% in the asset. if price < buy_threshold: order_target_percent( context.asset, 1.0, ) elif price > sell_threshold: order_target_percent( context.asset, 0.5, ) else: order_target_percent( context.asset, 0.75, ) record( price=price, leverage=context.account.leverage, sma=sma, std=std, buy_threshold=buy_threshold, sell_threshold=sell_threshold, )
def handle_data(context, data): price = data.current(context.asset, 'price') record(price=price, cash=context.portfolio.cash) if not context.bought: order_target_percent(context.asset, 1) context.bought = True if get_datetime().date() == context.end_date: order_target_percent(context.asset, 0)
def handle_data(context, data): value = context.portfolio.portfolio_value base = 0 context.day += 1 buyList = [] for obj in context.univers: market = context.objects[obj] if context.mailema: if not context.basePrice[obj]: context.basePrice[obj] = data.current(symbol(obj), 'price') else: base += data.current(symbol(obj), 'price') / context.basePrice[obj] - 1 if not market.ATRs: market.setATRs(data) market.update(data) market.updateCurrentPrice(data) oprt = market.getOperator() if oprt in ['entry', 'add']: if not context.mailema: context.mailema = 1 allM = context.portfolio.portfolio_value Qvalue = market.getUnit(allM) * data.current(symbol(obj), 'price') #print context.day,'cash: ',context.portfolio.cash #print context.day,'all:',context.portfolio.portfolio_value print context.day, 'oder: ', Qvalue #order_value(symbol(obj),Qvalue) buyList.append([symbol(obj), Qvalue]) elif oprt in ['outry', 'clean']: #print context.day,'cash: ',context.portfolio.cash #print context.day,'all:',context.portfolio.portfolio_value order_target_percent(symbol(obj), 0.0001) allBuyM = 0 for each in buyList: allBuyM += each[1] if allBuyM > context.portfolio.cash and allBuyM > 0: tranRate = context.portfolio.cash / allBuyM for each in buyList: if each[1] * tranRate > 10: order_value(each[0], each[1] * tranRate) else: for each in buyList: if each[1] > 10: order_value(each[0], each[1]) Cash = context.portfolio.cash print context.day, 'cash: ', context.portfolio.cash print context.day, 'all:', context.portfolio.portfolio_value #print context.slippage if context.mailema: record('Vreturn', ((context.portfolio.portfolio_value / 10000) - 1)) base /= len(context.univers) record('base', base)
def handle_data(context, data): # The last known prices of current date and the day before yesterday_price, current_price = data.history(context.asset, 'price', 2, '1T') # Calculate return simple_return = current_price / yesterday_price # Calculate log return log_return = np.log(current_price) - np.log(yesterday_price) record(price=current_price, simple_return=simple_return, log_return=log_return)
def handle_data(context, data): # order once. at the beginning if context.i == 0: order_target_percent(context.asset, 1.0) record( price=data.current(context.asset, 'price'), volume=data.current(context.asset, 'volume'), ) context.i += 1
def _handle_data(self, context, data): """ Arguments: context () data () """ for market, agent in self.agents.items(): agent.trade(context, data) record(cash=context.portfolio.cash)
def handle_data(context, data): price = data.current(context.asset, 'price') record(price=price, cash=context.portfolio.cash) if not context.bought: order(context.asset, 1) context.bought = True if context.bought and not context.sold and price > 6300: order(context.asset, -1) context.sold = True
def handle_data(context, data): current_time = get_datetime().time() # Get data A = data.history( context.A, 'price', bar_count=context.n_modelling, frequency=context.tf, ) B = data.history( context.B, 'price', bar_count=context.n_modelling, frequency=context.tf, ) # Calc returns and spread A_return = A.pct_change() B_return = B.pct_change() spread = A_return - B_return zscore = (spread.iloc[-1] - spread.mean()) / spread.std() # Close positions if context.portfolio.positions[ context.B].amount < 0 and zscore >= -context.z_signal_out: order_target_percent(context.A, 0.0) order_target_percent(context.B, 0.0) if context.portfolio.positions[ context.B].amount > 0 and zscore <= context.z_signal_out: order_target_percent(context.A, 0.0) order_target_percent(context.B, 0.0) # Check minimal allowed spread value if (abs(spread[-1]) >= context.min_spread ): # and np.sign(A_return[-1] * B_return[-1]) < 0: # Long and Short positions for assets if context.portfolio.positions[ context.B].amount == 0 and zscore > context.z_signal_in: order_target_percent(context.A, -0.5 * context.leverage) order_target_percent(context.B, 0.5 * context.leverage) if context.portfolio.positions[ context.B].amount == 0 and zscore < -context.z_signal_in: order_target_percent(context.A, 0.5 * context.leverage) order_target_percent(context.B, -0.5 * context.leverage) record(A_return=A_return[-1], B_return=B_return[-1], spread=spread[-1], zscore=zscore)
def handle_data(context, data): context.i += 1 # context.i % 1 == 0 cash = context.portfolio.cash # Retrieve current asset price from pricing data price = data.current(context.asset, 'price') record( price=price, volume=data.current(context.asset, 'volume'), cash=cash, starting_cash=context.portfolio.starting_cash, ) #if(context.i % 60 == 0): ''' Highs = data.history(context.asset, 'high', bar_count=30, frequency="1M", ) Lows = data.history(context.asset, 'low', bar_count=30, frequency="1M", ) Closes = data.history(context.asset, 'close', bar_count=30, frequency="1M", ) Prices = data.history(context.asset, 'price', bar_count=30, frequency="1M", ) ATR = Highs[0] - Lows[0] for i in range(1, 29): ATR = ATR + max((Highs[i] - Lows[i]), abs(Highs[i] - Closes[i - 1]), abs(Lows[i] - Closes[i - 1])) ATR = ATR / 29 ''' if (price > 1.01 and context.state == "bought"): order_target_percent(context.asset, 0) context.state = "sold" elif (price <= 1.01 and context.state == "sold"): order(context.asset, 1) context.state = "bought" context.boughtPrice = price
def handle_data_api(context, data): if context.incr == 0: assert 0 not in context.portfolio.positions else: assert context.portfolio.positions[0].amount == \ context.incr, "Orders not filled immediately." assert context.portfolio.positions[0].last_sale_price == \ data.current(sid(0), "price"), \ "Orders not filled at current price." context.incr += 1 order(sid(0), 1) record(incr=context.incr)
def save_record(self): record(price=self.context.cmx_signal.price, fair_price=self.context.cmx_signal.fair_price, zscore=self.context.cmx_signal.zscore, price_change=self.context.cmx_signal.price_change, invent_long_entry=self.context.cmx_signal.fair_price - self.context.invent_pm * self.context.cmx_signal.std, invent_short_entry=self.context.cmx_signal.fair_price + self.context.invent_pm * self.context.cmx_signal.std, base_pos=self.context.cmx_risk.base_pos, quote_pos=self.context.cmx_risk.quote_pos, cmx_pnl=self.context.cmx_risk.pnl, cmx_max_pos=self.context.risk_max_long_pos)
def _handle_data_rsi_only(context, data): price = data.current(context.asset, 'close') log.info('got price {price}'.format(price=price)) if price is np.nan: log.warn('no pricing data') return if context.base_price is None: context.base_price = price try: prices = data.history( context.asset, fields='price', bar_count=20, frequency='30T' ) except Exception as e: log.warn('historical data not available: '.format(e)) return rsi = talib.RSI(prices.values, timeperiod=16)[-1] log.info('got rsi {}'.format(rsi)) signal = None if rsi < context.RSI_OVERSOLD: signal = 'long' # Making sure that the price is still current price = data.current(context.asset, 'close') cash = context.portfolio.cash log.info( 'base currency available: {cash}, cap: {cap}'.format( cash=cash, cap=context.MAX_HOLDINGS ) ) volume = data.current(context.asset, 'volume') price_change = (price - context.base_price) / context.base_price record( price=price, price_change=price_change, rsi=rsi, volume=volume, cash=cash, starting_cash=context.portfolio.starting_cash, leverage=context.account.leverage, ) _handle_buy_sell_decision(context, data, signal, price)
def handle_data(context, data): price = data.current(context.asset, 'price') record(btc=price) # Only ordering if it does not have any position to avoid trying some # tiny orders with the leftover btc pos_amount = context.portfolio.positions[context.asset].amount if pos_amount > 0: return # Adding a limit price to workaround an issue with performance # calculations of market orders order_target_percent( context.asset, 1, limit_price=price * 1.01 )
def handle_data(context, data): context.i += 1 starting_cash = context.portfolio.starting_cash target_hodl_value = context.TARGET_HODL_RATIO * starting_cash reserve_value = context.RESERVE_RATIO * starting_cash # Cancel any outstanding orders orders = get_open_orders(context.asset) or [] for order in orders: cancel_order(order) # Stop buying after passing the reserve threshold cash = context.portfolio.cash if cash <= reserve_value: context.is_buying = False # Retrieve current asset price from pricing data price = data.current(context.asset, 'price') # Check if still buying and could (approximately) afford another purchase if context.is_buying and cash > price: print('buying') # Place order to make position in asset equal to target_hodl_value order_target_value( context.asset, target_hodl_value, limit_price=price * 1.1, ) record( price=price, volume=data.current(context.asset, 'volume'), cash=cash, starting_cash=context.portfolio.starting_cash, leverage=context.account.leverage, )
def default_handle_data(context, data): context.curr_minute = data.current_dt context.counter += 1 if context.candles_sample_rate == 1: context.i += 1 elif context.counter % context.candles_sample_rate != 0: context.i += 1 return if context.i < context.parameters.SKIP_FIRST_CANDLES: return context.candles_open = data.history( context.coin_pair, 'open', bar_count=context.candles_buffer_size, frequency=context.candles_frequency) context.candles_high = data.history( context.coin_pair, 'high', bar_count=context.candles_buffer_size, frequency=context.candles_frequency) context.candles_low = data.history( context.coin_pair, 'low', bar_count=context.candles_buffer_size, frequency=context.candles_frequency) context.candles_close = data.history( context.coin_pair, 'price', bar_count=context.candles_buffer_size, frequency=context.candles_frequency) context.candles_volume = data.history( context.coin_pair, 'volume', bar_count=context.candles_buffer_size, frequency=context.candles_frequency) # FIXME: Here is the error! # The candles_close frame shows more or less always a value of 94, while # bitcoin price is very different from that print(context.candles_close) context.base_prices = context.candles_close cash = context.portfolio.cash amount = context.portfolio.positions[context.coin_pair].amount price = data.current(context.coin_pair, 'price') order_id = None context.last_base_price = context.base_prices[-2] context.curr_base_price = context.base_prices[-1] # TA calculations # ... # Sanity checks # assert cash >= 0 if cash < 0: import ipdb; ipdb.set_trace() # BREAKPOINT print_facts(context) print_facts_telegram(context) # Order management net_shares = 0 if context.counter == 2: brute_shares = (cash / price) * context.parameters.BUY_PERCENTAGE share_commission_fee = brute_shares * context.parameters.COMMISSION_FEE net_shares = brute_shares - share_commission_fee buy_order_id = order(context.coin_pair, net_shares) if context.counter == 3: brute_shares = amount * context.parameters.SELL_PERCENTAGE share_commission_fee = brute_shares * context.parameters.COMMISSION_FEE net_shares = -(brute_shares - share_commission_fee) sell_order_id = order(context.coin_pair, net_shares) # Record record( price=price, foo='bar', # volume=current['volume'], # price_change=price_change, # Metrics cash=cash, # buy=context.buy, # sell=context.sell )
def handle_data(context, data): # This handle_data function is where the real work is done. Our data is # minute-level tick data, and each minute is called a frame. This function # runs on each frame of the data. # We flag the first period of each day. # Since cryptocurrencies trade 24/7 the `before_trading_starts` handle # would only execute once. This method works with minute and daily # frequencies. today = data.current_dt.floor('1D') if today != context.current_day: context.traded_today = False context.current_day = today # We're computing the volume-weighted-average-price of the security # defined above, in the context.market variable. For this example, we're # using three bars on the 15 min bars. # The frequency attribute determine the bar size. We use this convention # for the frequency alias: # http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases prices = data.history( context.market, fields='close', bar_count=50, frequency=context.CANDLE_SIZE ) # Ta-lib calculates various technical indicator based on price and # volume arrays. # In this example, we are comp rsi = talib.RSI(prices.values, timeperiod=14) # We need a variable for the current price of the security to compare to # the average. Since we are requesting two fields, data.current() # returns a DataFrame with current = data.current(context.market, fields=['close', 'volume']) price = current['close'] # If base_price is not set, we use the current value. This is the # price at the first bar which we reference to calculate price_change. if context.base_price is None: context.base_price = price price_change = (price - context.base_price) / context.base_price cash = context.portfolio.cash # Now that we've collected all current data for this frame, we use # the record() method to save it. This data will be available as # a parameter of the analyze() function for further analysis. record( volume=current['volume'], price=price, price_change=price_change, rsi=rsi[-1], cash=cash ) # We are trying to avoid over-trading by limiting our trades to # one per day. if context.traded_today: return # TODO: retest with open orders # Since we are using limit orders, some orders may not execute immediately # we wait until all orders are executed before considering more trades. orders = context.blotter.open_orders if len(orders) > 0: log.info('exiting because orders are open: {}'.format(orders)) return # Exit if we cannot trade if not data.can_trade(context.market): return # Another powerful built-in feature of the Catalyst backtester is the # portfolio object. The portfolio object tracks your positions, cash, # cost basis of specific holdings, and more. In this line, we calculate # how long or short our position is at this minute. pos_amount = context.portfolio.positions[context.market].amount if rsi[-1] <= context.RSI_OVERSOLD and pos_amount == 0: log.info( '{}: buying - price: {}, rsi: {}'.format( data.current_dt, price, rsi[-1] ) ) # Set a style for limit orders, limit_price = price * 1.005 order_target_percent( context.market, 1, limit_price=limit_price ) context.traded_today = True elif rsi[-1] >= context.RSI_OVERBOUGHT and pos_amount > 0: log.info( '{}: selling - price: {}, rsi: {}'.format( data.current_dt, price, rsi[-1] ) ) limit_price = price * 0.995 order_target_percent( context.market, 0, limit_price=limit_price ) context.traded_today = True
def handle_data(context, data): order(context.asset, 1) record(btc=data.current(context.asset, 'price'))
def handle_data(context, data): # define the windows for the moving averages short_window = 50 long_window = 200 # Skip as many bars as long_window to properly compute the average context.i += 1 if context.i < long_window: return # Compute moving averages calling data.history() for each # moving average with the appropriate parameters. We choose to use # minute bars for this simulation -> freq="1m" # Returns a pandas dataframe. short_data = data.history(context.asset, 'price', bar_count=short_window, frequency="1T", ) short_mavg = short_data.mean() long_data = data.history(context.asset, 'price', bar_count=long_window, frequency="1T", ) long_mavg = long_data.mean() # Let's keep the price of our asset in a more handy variable price = data.current(context.asset, 'price') # If base_price is not set, we use the current value. This is the # price at the first bar which we reference to calculate price_change. if context.base_price is None: context.base_price = price price_change = (price - context.base_price) / context.base_price # Save values for later inspection record(price=price, cash=context.portfolio.cash, price_change=price_change, short_mavg=short_mavg, long_mavg=long_mavg) # Since we are using limit orders, some orders may not execute immediately # we wait until all orders are executed before considering more trades. orders = get_open_orders(context.asset) if len(orders) > 0: return # Exit if we cannot trade if not data.can_trade(context.asset): return # We check what's our position on our portfolio and trade accordingly pos_amount = context.portfolio.positions[context.asset].amount # Trading logic if short_mavg > long_mavg and pos_amount == 0: # we buy 100% of our portfolio for this asset order_target_percent(context.asset, 1) elif short_mavg < long_mavg and pos_amount > 0: # we sell all our positions for this asset order_target_percent(context.asset, 0)
def _handle_data(context, data): price = data.current(context.asset, 'price') log.info('got price {price}'.format(price=price)) prices = data.history( context.asset, fields='price', bar_count=20, frequency='1D' ) rsi = talib.RSI(prices.values, timeperiod=14)[-1] log.info('got rsi: {}'.format(rsi)) # Buying more when RSI is low, this should lower our cost basis if rsi <= 30: buy_increment = 1 elif rsi <= 40: buy_increment = 0.5 elif rsi <= 70: buy_increment = 0.2 else: buy_increment = 0.1 cash = context.portfolio.cash log.info('base currency available: {cash}'.format(cash=cash)) record( price=price, rsi=rsi, ) orders = context.blotter.open_orders if orders: log.info('skipping bar until all open orders execute') return is_buy = False cost_basis = None if context.asset in context.portfolio.positions: position = context.portfolio.positions[context.asset] cost_basis = position.cost_basis log.info( 'found {amount} positions with cost basis {cost_basis}'.format( amount=position.amount, cost_basis=cost_basis ) ) if position.amount >= context.TARGET_POSITIONS: log.info('reached positions target: {}'.format(position.amount)) return if price < cost_basis: is_buy = True elif (position.amount > 0 and price > cost_basis * (1 + context.PROFIT_TARGET)): profit = (price * position.amount) - (cost_basis * position.amount) log.info('closing position, taking profit: {}'.format(profit)) order_target_percent( asset=context.asset, target=0, limit_price=price * (1 - context.SLIPPAGE_ALLOWED), ) else: log.info('no buy or sell opportunity found') else: is_buy = True if is_buy: if buy_increment is None: log.info('the rsi is too high to consider buying {}'.format(rsi)) return if price * buy_increment > cash: log.info('not enough base currency to consider buying') return log.info( 'buying position cheaper than cost basis {} < {}'.format( price, cost_basis ) ) order( asset=context.asset, amount=buy_increment, limit_price=price * (1 + context.SLIPPAGE_ALLOWED) )
def handle_data(context, data): order(context.assets[0], 1) prices = data.current(context.assets, 'price') record(price=prices) pass
def handle_data(context, data): log.info('handling bar {}'.format(data.current_dt)) buying_price = data.current( context.trading_pairs[context.buying_exchange], 'price') log.info('price on buying exchange {exchange}: {price}'.format( exchange=context.buying_exchange.name.upper(), price=buying_price, )) selling_price = data.current( context.trading_pairs[context.selling_exchange], 'price') log.info('price on selling exchange {exchange}: {price}'.format( exchange=context.selling_exchange.name.upper(), price=selling_price, )) # If for example, # selling price = 50 # buying price = 25 # expected gap = 1 # If follows that, # selling price - buying price / buying price # 50 - 25 / 25 = 1 gap = (selling_price - buying_price) / buying_price log.info( 'the price gap: {gap} ({gap_percent}%)'.format( gap=gap, gap_percent=gap * 100 ) ) record(buying_price=buying_price, selling_price=selling_price, gap=gap) # Waiting for orders to close before initiating new ones for exchange in context.trading_pairs: asset = context.trading_pairs[exchange] orders = get_open_orders(asset) if orders: log.info( 'found {order_count} open orders on {exchange_name} ' 'skipping bar until all open orders execute'.format( order_count=len(orders), exchange_name=exchange.name ) ) return # Consider the least ambitious entry point first # Override of wider gap is found entry_points = sorted( context.entry_points, key=lambda point: point['gap'], ) buy_amount = None for entry_point in entry_points: if gap > entry_point['gap']: buy_amount = entry_point['amount'] if buy_amount: log.info('found buy trigger for amount: {}'.format(buy_amount)) place_orders( context=context, amount=buy_amount, buying_price=buying_price, selling_price=selling_price, action='enter' ) else: # Consider the narrowest exit gap first # Override of wider gap is found exit_points = sorted( context.exit_points, key=lambda point: point['gap'], reverse=True ) sell_amount = None for exit_point in exit_points: if gap < exit_point['gap']: sell_amount = exit_point['amount'] if sell_amount: log.info('found sell trigger for amount: {}'.format(sell_amount)) place_orders( context=context, amount=sell_amount, buying_price=buying_price, selling_price=selling_price, action='exit' )
def handle_data(self, data): self.incr += 1 self.record(incr=self.incr) name = 'name' self.record(name, self.incr) record(name, self.incr, 'name2', 2, name3=self.incr)
def handle_data(context, data): # Only rebalance at the beggining of the algorithm execution and # every multiple of the rebalance period if context.i == 0 or context.i % context.rebalance_period == 0: n = context.window prices = data.history(context.assets, fields='price', bar_count=n + 1, frequency='1d') pr = np.asmatrix(prices) t_prices = prices.iloc[1:n + 1] t_val = t_prices.values tminus_prices = prices.iloc[0:n] tminus_val = tminus_prices.values # Compute daily returns (r) r = np.asmatrix(t_val / tminus_val - 1) # Compute the expected returns of each asset with the average # daily return for the selected time window m = np.asmatrix(np.mean(r, axis=0)) # ### stds = np.std(r, axis=0) # Compute excess returns matrix (xr) xr = r - m # Matrix algebra to get variance-covariance matrix cov_m = np.dot(np.transpose(xr), xr) / n # Compute asset correlation matrix (informative only) corr_m = cov_m / np.dot(np.transpose(stds), stds) # Define portfolio optimization parameters n_portfolios = 50000 results_array = np.zeros((3 + context.nassets, n_portfolios)) for p in xrange(n_portfolios): weights = np.random.random(context.nassets) weights /= np.sum(weights) w = np.asmatrix(weights) p_r = np.sum(np.dot(w, np.transpose(m))) * 365 p_std = np.sqrt(np.dot(np.dot(w, cov_m), np.transpose(w))) * np.sqrt(365) # store results in results array results_array[0, p] = p_r results_array[1, p] = p_std # store Sharpe Ratio (return / volatility) - risk free rate element # excluded for simplicity results_array[2, p] = results_array[0, p] / results_array[1, p] i = 0 for iw in weights: results_array[3 + i, p] = weights[i] i += 1 # convert results array to Pandas DataFrame results_frame = pd.DataFrame(np.transpose(results_array), columns=['r', 'stdev', 'sharpe'] + context.assets) # locate position of portfolio with highest Sharpe Ratio max_sharpe_port = results_frame.iloc[results_frame['sharpe'].idxmax()] # locate positon of portfolio with minimum standard deviation # min_vol_port = results_frame.iloc[results_frame['stdev'].idxmin()] # order optimal weights for each asset for asset in context.assets: if data.can_trade(asset): order_target_percent(asset, max_sharpe_port[asset]) # create scatter plot coloured by Sharpe Ratio plt.scatter(results_frame.stdev, results_frame.r, c=results_frame.sharpe, cmap='RdYlGn') plt.xlabel('Volatility') plt.ylabel('Returns') plt.colorbar() # plot red star to highlight position of portfolio # with highest Sharpe Ratio plt.scatter(max_sharpe_port[1], max_sharpe_port[0], marker='o', color='b', s=200) # plot green star to highlight position of minimum variance portfolio plt.show() print(max_sharpe_port) record(pr=pr, r=r, m=m, stds=stds, max_sharpe_port=max_sharpe_port, corr_m=corr_m) context.i += 1