def check_stop(self, tick): if self.virtual_stop: if tick['L'] < self.virtual_stop: stop = tick['L'] * 0.99 self.virtual_stop = None if not self.physical_stop or stop > self.physical_stop: self.log('Virtual stop reached. ' 'Putting a physical stop @ %s' % btc2str(stop)) self.sell_stop(self.quantity, stop) self.physical_stop = stop else: self.log('Virtual stop reached. ' 'Not lowering physical stop %s < %s' % (btc2str(stop), btc2str(self.physical_stop))) if self.physical_stop: if self.monitor_order_completion('stop '): past_orders = self.exch.get_order_history(self.pair) if len(past_orders) == 0: self.log('Unable to find stop order. Aborting.') sys.exit(1) stop_order = past_orders[0] self.compute_gains(tick, stop_order) self.physical_stop = None # buy order has been sent return True if self.order and self.order.is_buy_order(): self.physical_stop = None return True return False
def process_tick_buying(self, tick, last_row): if self.monitor_order_completion('buy '): past_orders = self.exch.get_order_history(self.pair) if len(past_orders) == 0: self.log('Unable to find buy order. Aborting.') sys.exit(1) buy_order = past_orders[0] self.entry = buy_order.data['PricePerUnit'] self.quantity = buy_order.data['Quantity'] self.cost = buy_order.data.get('Commission', 0) self.log("bought %f @ %s Fees %s" % (self.quantity, btc2str(self.entry), btc2str(self.cost))) # in recovery mode we can switch to 'top directly if tick['C'] > last_row['BBM']: self.status = 'top' else: self.status = 'middle' # safe bet for recovery mode self.set_stop(tick, min(last_row['BBL'], self.entry * 0.95)) elif self.entry < last_row['L']: self.log('entry %s < low %s -> canceling order' % (btc2str(self.entry), btc2str(last_row['L']))) self.do_cancel_order() self.entry = None self.quantity = 0 self.status = 'searching'
def __init__(self, exch, name, arguments, buy): parser = argparse.ArgumentParser(prog=name) parser.add_argument( '-r', "--range", help='floating number to compute buy range. Default 0.09.', type=float, default=0.09) parser.add_argument('-t', "--trailing", help='force trailing mode', action="store_true") parser.add_argument( '-p', "--period", help='initial period to check acceleration in trailing mode.' ' Default 60.', type=int, default=60) parser.add_argument('pair', help='pair of crypto like BTC-ETH') parser.add_argument('quantity', help='quantity of coins or ALL') parser.add_argument('stop', help='stop level') parser.add_argument('entry', help='entry level') parser.add_argument('target', help='target level') args = parser.parse_args(arguments) self.pair = args.pair self.stop_price = str2btc(args.stop) self.entry_price = str2btc(args.entry) self.target_price = str2btc(args.target) self.trail_price = None self.trailing = args.trailing self.df = None self.period = args.period self.range = args.range self.tick = None if args.quantity == 'ALL': if self.balance == 0: self.log('ALL specified and no existing position. Aborting.') sys.exit(1) self.quantity = self.balance else: self.quantity = float(args.quantity) super().__init__(exch, name, arguments, buy) print( '%s %s stop=%s entry=%s target=%s quantity=%.3f\n' ' trailing=%s period=%d range=%f buy=%s' % (self.name, self.pair, btc2str(self.stop_price), btc2str(self.entry_price), btc2str(self.target_price), self.quantity, self.trailing, self.period, self.range, self.buy)) if self.buy: if not self.do_buy_order(self.stop_price, self.entry_price, self.range): sys.exit(1) self.status = 'buying'
def status2str(self): if self.trailing: return 'trailing(%s)' % btc2str(self.trail_price) elif self.status == 'down': return 'down(%s)' % btc2str(self.stop_price) elif self.status == 'up': return 'up(%s)' % btc2str(self.target_price) else: return self.status
def __init__(self, exch, name, args, buy): if len(args) < 4: print('Usage: %s [-b] <pair> ALL|<quantity> ' '<stop price> <entry price> ' '<target1 price> [<target2 price>...]') sys.exit(1) super().__init__(exch, name, args, buy) self.stop_price = str2btc(args[2]) self.entry_price = str2btc(args[3]) self.number = len(args) - 4 self.targets = [str2btc(arg) for arg in args[4:]] reached = [-arg for arg in self.targets if arg < 0] stops = [self.stop_price, self.entry_price] + \ [abs(arg) for arg in self.targets] self.targets = [arg if arg > 0 else None for arg in self.targets] self.stop_entry = {} for idx in range(len(stops) - 1): self.stop_entry[stops[idx + 1]] = stops[idx] if len(reached) > 0: self.stop_price = self.stop_entry[reached[-1]] self.entry_price = reached[-1] if args[1] == 'ALL': if self.balance == 0: self.log('ALL specified and no existing position. Aborting.') sys.exit(1) self.quantity = self.balance else: self.quantity = float(args[1]) self.log('%s %s stop=%s entry=%s quantity=%.3f buy=%s' % (self.name, self.pair, btc2str(self.stop_price), btc2str(self.entry_price), self.quantity, self.buy)) self.log('%d targets: %s' % (self.number, ' '.join([btc2str(t) if t else 'reached' for t in self.targets]))) if self.buy: self.status = 'buying' if not self.do_buy_order(self.stop_price, self.entry_price): sys.exit(1) else: self.status = 'unknown' for order in self.update_open_orders(): self.log('Canceling %s' % order) self.exch.cancel_order(order) self.order = None
def compute_gains(self, tick, order): price = order.data['PricePerUnit'] quantity = order.data['Quantity'] self.cost += order.data['Commission'] amount = price * quantity - self.cost self.log('sold %f @ %s => %f %f %.2f%% (buy price=%s)' % (quantity, btc2str(price), amount, self.amount, (amount / self.amount - 1) * 100, btc2str(self.entry))) self.amount = amount self.quantity = 0 self.entry = None self.virtual_stop = None self.status = 'searching'
def check_stop(self, tick): if self.stop: if tick['L'] < self.stop: stop = tick['L'] * 0.99 self.log('stop reached. Putting a physical stop @ %s' % btc2str(stop)) self.sell_stop(self.quantity, stop) self.stop = None self.check_order() self.stop_order = self.order or True return True if self.stop_order: self.check_order() if self.stop_order is True: self.stop_order = self.order or True if self.stop_order is not True: # order is no longer open if not self.order: self.exch.update_order(self.stop_order) self.compute_gains(tick, self.stop_order) self.stop_order = None # buy order has been sent elif self.order.is_buy_order(): self.stop_order = None return True return False
def process_tick_position(self, tick): self.check_order() last = tick['C'] if last < self.entry_price: if (tick['L'] < self.stop_price and self.monitor_order_completion('Stop reached: ')): return False elif self.status != 'down': for order in self.update_open_orders(): self.log('Canceling %s' % order) self.exch.cancel_order(order) if len(self.update_open_orders()) != 0: return True self.order = None remain = len([t for t in self.targets if t]) self.sell_stop(self.quantity * remain / self.number, self.stop_price) self.status = 'down' else: if (tick['H'] > self.targets[-1] and self.monitor_order_completion('Last target reached: ')): return False elif self.status != 'up': for limit in self.targets[:-1]: if limit: self.log('Limit order %.3f @ %s' % (self.quantity / self.number, btc2str(limit))) self.sell_limit(self.quantity / self.number, limit) self.order = None if self.targets[-1]: self.log('Limit order %.3f @ %s' % (self.quantity - (self.quantity * (self.number - 1)), btc2str(self.targets[-1]))) self.sell_limit(self.quantity - (self.quantity * (self.number - 1) / self.number), self.targets[-1]) self.status = 'up' else: for idx in range(len(self.targets)): if self.targets[idx] and tick['H'] >= self.targets[idx]: self.stop_price = self.stop_entry[self.targets[idx]] self.entry_price = self.targets[idx] self.log('target %d reached (%s). ' 'new stop=%s new entry=%s' % (idx + 1, btc2str(self.targets[idx]), btc2str(self.stop_price), btc2str(self.entry_price))) self.targets[idx] = None self.log('%s %s %s-%s' % (self.status, btc2str(tick['C']), btc2str(tick['L']), btc2str(tick['H']))) return True
def process_tick(self): self.update_dataframe(self.tick) # Put a stop if needed but let the trade logic continue if it is not # reached self.check_stop(self.tick) self.dispatch_tick(self.status, self.tick) if self.status not in ('midnight', 'nine'): self.log('%s %s %s-%s %s (%f x %s)' % (self.status, btc2str(self.tick['C']), btc2str(self.tick['L']), btc2str(self.tick['H']), btc2str(self.amount), self.quantity, btc2str(self.entry))) return(self.amount > 0)
def process_tick_nine(self, tick): if tick['T'].hour == 9: if tick['C'] >= self.midnight_price * 1.05: self.status = 'buying' self.entry = tick['C'] self.quantity = self.amount / self.entry self.send_order(self.exch.buy_limit, self.pair, self.quantity, self.entry) self.log('%s %f @ %s' % (green('buying'), self.quantity, btc2str(self.entry))) else: self.log('%s: %s >= %s. retrying tomorrow. %.3f' % (red('no up trend'), btc2str(tick['C']), btc2str(self.midnight_price * 1.05), self.amount)) self.status = 'midnight'
def __init__(self, exch, name, arguments, buy): parser = argparse.ArgumentParser(prog=name) parser.add_argument('pair', help='pair of crypto like BTC-ETH') parser.add_argument('amount', help='quantity of currency to use for the trade', type=float) args = parser.parse_args(arguments) self.pair = args.pair self.amount = args.amount self.entry = None self.stop = None self.stop_order = None self.cost = 0 self.quantity = 0 super().__init__(exch, name, arguments, buy) self.ticks = self.init_dataframes() if buy: last_row = self.df.iloc[-1] if last_row.name.hour > 10: self.status = 'midnight' else: idx = -2 while True: row = self.df.iloc[idx] if row.name.hour == 0 and row.name.minute == 0: self.midnight_price = row['O'] self.log('Midnight price %s' % btc2str(self.midnight_price)) self.status = 'nine' break idx -= 1 else: self.status = 'midnight' else: self.status = 'recovering' self.log('%s amount=%s %s' % (name, btc2str(self.amount), self.status))
def process_tick_position(self, tick): self.check_order() last = tick['C'] if last < self.entry_price: if (tick['L'] < self.stop_price and self.monitor_order_completion('Stop reached: ')): return False elif self.status != 'down': self.sell_stop(self.quantity, self.stop_price) self.status = 'down' else: if self.trailing or tick['H'] > self.target_price: if not self.trailing: if not self.monitor_order_completion('Target reached: '): return True self.trailing = True if (self.trail_price and tick['L'] < self.trail_price and self.monitor_order_completion('Stop reached: ')): return False # do the trend following if self.df is None: self.init_dataframes() self.update_dataframe(tick) trail_price = self.compute_stop() if trail_price != self.trail_price: self.log('new trailing stop %s (prev %s) (period %d mn)' % (btc2str(trail_price), btc2str( self.trail_price), self.period)) self.trail_price = trail_price self.sell_stop(self.quantity / 2, self.trail_price) elif self.status != 'up': self.sell_limit(self.quantity / 2, self.target_price) self.status = 'up' self.log('%s %s %s-%s' % (self.status2str(), btc2str( tick['C']), btc2str(tick['L']), btc2str(tick['H']))) return True
def process_tick_searching(self, tick, last_row): volok = (last_row['V'] < last_row['VMA20']) priceok = (tick['L'] < (last_row['BBL'] * self.selling_pressure(last_row))) bbok = (last_row['BBW'] > self.percent) self.log('%s(%.2f < %.2f) %s(%s < %s) %s(%.2f > %.2f)' % (green('volok') if volok else red('volko'), last_row['V'], last_row['VMA20'], green('priceok') if priceok else red('priceko'), btc2str(tick['L']), btc2str(last_row['BBL']), green('bbok') if bbok else red('bbko'), last_row['BBW'], self.percent)) if volok and priceok and bbok: self.status = 'buying' self.entry = last_row['L'] self.quantity = self.amount / self.entry self.send_order(self.exch.buy_limit, self.pair, self.quantity, self.entry) self.log('buying %f @ %s' % (self.quantity, btc2str(self.entry)))
def process_tick(self): self.update_dataframe(self.tick) ndf = self.resample_dataframes(self.period) BB(ndf) MA(ndf, 20, 'V', 'VMA20') last_row = ndf.iloc[-2] # Put a stop if needed but let the trade logic continue if it is not # reached self.check_stop(self.tick) self.dispatch_tick(self.status, self.tick, last_row) self.log('%s %s %s-%s %.3f (%f x %s)' % (self.status, btc2str(self.tick['C']), btc2str(self.tick['L']), btc2str(self.tick['H']), self.amount, self.quantity, btc2str(self.entry))) del ndf return(self.amount > 0)
def process_tick(self): self.update_dataframe(self.tick) ndf = self.resample_dataframes(self.period) BB(ndf) MA(ndf, 20, 'V', 'VMA20') RSI(ndf) ATR_STP(ndf) last_row = ndf.iloc[-2] # Put a stop if needed but let the trade logic continue if it is not # reached self.check_stop(self.tick) self.dispatch_tick(self.status, self.tick, last_row) if self.entry: percent = ((self.tick['C'] / self.entry) - 1) * 100 else: percent = 0 self.log('%s %s %s-%s %.3f (%f x %s) vstop=%s pstop=%s %.2f%%' % (self.status, btc2str(self.tick['C']), btc2str(self.tick['L']), btc2str(self.tick['H']), self.amount, self.quantity, btc2str(self.entry), btc2str(self.virtual_stop), btc2str(self.physical_stop), percent)) del ndf return(self.amount > 0)
def process_tick(self): self.check_order() last = self.tick['C'] if last < self.middle_price: if (self.tick['L'] < self.stop_price and self.monitor_order_completion('Stop reached: ')): return False elif self.status != 'down': self.sell_stop(self.quantity, self.stop_price) self.status = 'down' else: if (self.tick['H'] > self.limit_price and self.monitor_order_completion('Limit reached: ')): return False elif self.status != 'up': self.sell_limit(self.quantity, self.limit_price) self.status = 'up' self.log('%s %s %s-%s' % (self.status, btc2str(self.tick['C']), btc2str(self.tick['L']), btc2str(self.tick['H']))) return True
def process_tick_buying(self, tick): if tick['T'].hour == 10: self.do_cancel_order() self.status = 'midnight' elif self.monitor_order_completion('buy'): past_orders = self.exch.get_order_history(self.pair) if len(past_orders) == 0: self.log('Unable to find buy order. Aborting.') sys.exit(1) buy_order = past_orders[0] self.entry = buy_order.data['PricePerUnit'] self.quantity = buy_order.data['Quantity'] self.cost = buy_order.data.get('Commission', 0) self.log("bought %f @ %s Fees %s" % (self.quantity, btc2str(self.entry), btc2str(self.cost))) self.target = self.entry + self.entry - self.midnight_price self.log('setting target to %s' % btc2str(self.target)) self.send_order(self.exch.sell_limit, self.pair, self.quantity, self.target) self.status = 'selling'
def __str__(self): d = self.data quantity = d['Quantity'] price = btc2str(d['Limit']) if d['OrderType'] == 'LIMIT_BUY': if d['IsConditional']: return('BUY STPLMT %.3f %s @ %s-%s' % (quantity, d['Exchange'], btc2str(d['ConditionTarget']), price)) else: return('BUY LMT %.3f %s @ %s' % (quantity, d['Exchange'], price)) else: if d['Condition'] != 'NONE': order_type = 'STP' price = btc2str(d['ConditionTarget']) else: order_type = 'LMT' price = btc2str(d['Limit']) return 'SELL %s %.3f %s @ %s' % (order_type, quantity, d['Exchange'], price)
def process_tick_searching(self, tick, last_row): RSI_THRESHOLD = 30 CORPSE_THRESHOLD = 0.2 rsiok = (last_row['RSI'] <= RSI_THRESHOLD) priceok = (tick['L'] < last_row['BBL']) bbok = (last_row['BBW'] >= self.percent) volok = (last_row['V'] < last_row['VMA20']) if last_row['H'] == last_row['C']: candle_corpse = 1 else: candle_corpse = ((last_row['H'] - min(last_row['C'], last_row['O'])) / (last_row['H'] - last_row['L'])) candleok = (candle_corpse <= CORPSE_THRESHOLD) or volok self.log('%s(%s <= %s) %s(%.1f < %f) %s(%.2f >= %.2f) ' '%s(%.2f <= %.2f or %s %.2f < %.2f)' % (green('priceok') if priceok else red('priceko'), btc2str(tick['L']), btc2str(last_row['BBL']), green('rsiok') if rsiok else red('rsiko'), last_row['RSI'], RSI_THRESHOLD, green('bbok') if bbok else red('bbko'), last_row['BBW'], self.percent, green('candleok') if candleok else red('candleko'), candle_corpse, CORPSE_THRESHOLD, green('volok') if volok else red('volko'), last_row['V'], last_row['VMA20'])) if rsiok and priceok and bbok and candleok: self.status = 'buying' self.entry = last_row['L'] self.quantity = self.amount / self.entry self.send_order(self.exch.buy_limit, self.pair, self.quantity, self.entry) self.log('buying %f @ %s' % (self.quantity, btc2str(self.entry))) self.middle = last_row['BBM'] self.top = last_row['BBU']
def compute_gains(self, order): price = order.data['PricePerUnit'] quantity = order.data['Quantity'] self.cost += order.data['Commission'] amount = price * quantity - self.cost self.log('sold %f @ %s => %f %f %.2f%%' % (quantity, btc2str(price), amount, self.amount, (amount / self.amount - 1) * 100)) self.amount = amount self.quantity = 0 self.entry = None self.stop = None self.stop_order = None self.status = 'midnight'
def buy_limit(self, pair, quantity, limit_price): self.log('BUY LMT %.3f %s %s' % (quantity, pair, btc2str(limit_price))) self.order = BittrexOrder( { 'OrderId': '1', 'Quantity': quantity, 'Limit': limit_price, 'Commission': limit_price * quantity * self.percent_fee, 'OrderType': 'LIMIT_BUY', 'IsConditional': False, 'Condition': 'NONE', 'Exchange': pair, 'PricePerUnit': limit_price }, id='3') self.orders.insert(0, self.order) return self.order
def sell_stop(self, pair, quantity, stop_price): self.log('SELL STP %.3f %s %s' % (quantity, pair, btc2str(stop_price))) self.order = BittrexOrder( { 'OrderId': '1', 'Quantity': quantity, 'Limit': stop_price / 2, 'Commission': stop_price * quantity * self.percent_fee, 'OrderType': 'LIMIT_SELL', 'IsConditional': True, 'Condition': 'LESSTHAN', 'ConditionTarget': stop_price, 'Exchange': pair, 'PricePerUnit': stop_price }, id='2') self.orders.insert(0, self.order) return self.order
def process_tick(self, tick): if self.order: self.log('ORDER %s' % self.order) if self.order.is_buy_order() and self.order.limit() >= tick['L']: self.log('BOUGHT') self.order = None elif self.order.is_sell_order(): if (not self.order.data['IsConditional'] and tick['H'] > self.order.limit()): self.log('SOLD LIMIT') self.order.data['PricePerUnit'] = ( (tick['H'] + tick['L']) / 2) self.order = None elif (self.order.data['IsConditional'] and self.order.data['ConditionTarget'] > tick['L']): self.order.data['PricePerUnit'] = ( (self.order.data['ConditionTarget'] + tick['L']) / 2) self.log('STOPPED @ %s' % btc2str(self.order.data['PricePerUnit'])) self.order = None
def check_stop(self, tick): if self.stop: if tick['L'] < self.stop: stop = tick['L'] * 0.99 self.log('stop reached. Putting a physical stop @ %s' % btc2str(stop)) self.sell_stop(self.quantity, stop) self.stop = None self.stop_order = True return True if self.stop_order: # buy order has been sent if self.order and self.order.is_buy_order(): self.stop_order = None elif self.monitor_order_completion('stop '): past_orders = self.exch.get_order_history(self.pair) if len(past_orders) == 0: self.log('Unable to find sell order. Aborting.') sys.exit(1) self.compute_gains(past_orders[0]) self.stop_order = None return True return False
def __init__(self, exch, name, arguments, buy): parser = argparse.ArgumentParser(prog=name) parser.add_argument( '-p', "--percent", help='percentage of the Bollinger band width to look for.' ' Default 0.05.', type=float, default=0.05) parser.add_argument('pair', help='pair of crypto like BTC-ETH') parser.add_argument('amount', help='quantity of currency to use for the trade', type=float) parser.add_argument('period', help='number of minutes to take decisions', type=int) args = parser.parse_args(arguments) self.pair = args.pair self.amount = args.amount self.period = args.period self.percent = args.percent if buy: self.status = 'searching' else: self.status = 'recovering' self.entry = None self.stop = None self.stop_order = None self.cost = 0 self.quantity = 0 super().__init__(exch, name, arguments, buy) self.ticks = self.init_dataframes() self.log('%s amount=%s period=%d mn percent=%.2f%%' % (name, btc2str(self.amount), self.period, self.percent * 100))
print('Usage: %s <market>' % sys.argv[0]) sys.exit(1) market = sys.argv[1] currency = market.split('-')[1] exch = BittrexExchange(True) orders = exch.get_order_history(market) for idx in range(len(orders)): if orders[idx].is_buy_order(): break print(orders[idx]) entry = orders[idx].quantity() * orders[idx].price_per_unit() total = 0 for i in range(idx): print(orders[i]) total += orders[i].quantity() * orders[i].price_per_unit() print('delta=%s percent=%.2f%%' % (btc2str(total - entry), (total / entry - 1) * 100)) price = orders[idx].price_per_unit() + (total - entry) / orders[idx].quantity() print('equivalent to have sold at %s x %.3f' % (btc2str(price), orders[idx].quantity()))
def process_tick(self): self.log('%s %s-%s' % (btc2str(self.tick['C']), btc2str( self.tick['L']), btc2str(self.tick['H']))) return True
def set_stop(self, tick, value): self.stop = value self.log('Setting virtual stop to %s' % btc2str(value))
def process_tick_midnight(self, tick): if tick['T'].hour == 0: self.midnight_price = tick['O'] self.log('Midnight price %s' % btc2str(self.midnight_price)) self.status = 'nine'
def buy_limit_range(self, pair, quantity, entry, val_max): self.log('BUY RNG %.3f %s %s-%s' % (quantity, pair, btc2str(entry), btc2str(val_max)))