class BotCandlestick(object): def __init__(self, period=300,open=None,close=None,high=None,low=None,priceAverage=None): self.current = None self.open = open self.close = close self.high = high self.low = low self.startTime = time.time() self.period = period self.output = BotLog() self.priceAverage = priceAverage def tick(self,price): self.current = float(price) if (self.open is None): self.open = self.current if ( (self.high is None) or (self.current > self.high) ): self.high = self.current if ( (self.low is None) or (self.current < self.low) ): self.low = self.current if ( time.time() >= ( self.startTime + self.period) ): self.close = self.current self.priceAverage = ( self.high + self.low + self.close ) / float(3) self.output.log("Open: "+str(self.open)+" Close: "+str(self.close)+" High: "+str(self.high)+" Low: "+str(self.low)+" Current: "+str(self.current)) def isClosed(self): if (self.close is not None): return True else: return False
class BotCandlestick(object): def __init__(self, period=None, open=None, close=None, high=None, low=None, typical_price=None): """""" self.output = BotLog() self.current = None self.open = open self.close = close self.high = high self.low = low self.period = period self.startTime = time.time() self.typical_price = typical_price def tick(self, price, **kwargs): self.current = float(price) # If it's a brand new price the open price hasn't been set yet # then the current price is the open price. if self.open is None: self.open = self.current # If it's a brand new price the high price hasn't been set yet, # or if the current price is greater than the current high # then set this current price as the high. if (self.high is None) or (self.current > self.high): self.high = self.current # If it's a brand new price the low price hasn't been set yet, # or if the current price is less than the current low # then set this current price as the low. if (self.low is None) or (self.current < self.low): self.low = self.current # If the current time is at or after the start time plus the period # (i.e. this will be the last price that goes into this candlestick before # it is added to the list of past candlesticks) then set this current price # as the closing price. if time.time() >= (self.startTime + (self.period * 60)): self.close = self.current # Determine the typical price over entire period of the candlestick. self.typical_price = (self.high + self.low + self.close) / float(3) # Show OHLC data on each tick self.output.log(" Open: " + str(self.open) + " Close: " + str(self.close) + " High: " + str(self.high) + " Low: " + str(self.low) + " Current: " + str(self.current)) statsd.histogram('candlestick.price.close', self.close, tags=['candlestick.price.close', 'bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.histogram('candlestick.price.high', self.high, tags=['candlestick.price.high', 'bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.histogram('candlestick.price.low', self.low, tags=['candlestick.price.low', 'bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.histogram('candlestick.price.typical_price', self.typical_price, tags=['candlestick.price.typical_price', 'bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) def isClosed(self): if self.close is not None: return True else: return False
class BotStrategy(object): def __init__(self): self.output = BotLog() self.prices = [] self.closes = [] # Needed for Momentum Indicator self.trades = [] self.currentPrice = "" self.currentClose = "" self.numSimulTrades = 1 self.indicators = BotIndicators() def tick(self, candlestick): print candlestick.priceAverage self.currentPrice = float(candlestick.priceAverage) self.prices.append(self.currentPrice) #self.currentClose = float(candlestick['close']) #self.closes.append(self.currentClose) self.output.log("Price: " + str(candlestick.priceAverage) + "\tMoving Average: " + str(self.indicators.movingAverage(self.prices, 15))) self.evaluatePositions() self.updateOpenTrades() self.showPositions() def evaluatePositions(self): openTrades = [] for trade in self.trades: if (trade.status == "OPEN"): openTrades.append(trade) if (len(openTrades) < self.numSimulTrades): if (self.currentPrice < self.indicators.movingAverage( self.prices, 15)): self.trades.append(BotTrade(self.currentPrice, stopLoss=.0001)) for trade in openTrades: if (self.currentPrice > self.indicators.movingAverage( self.prices, 15)): trade.close(self.currentPrice) def updateOpenTrades(self): for trade in self.trades: if (trade.status == "OPEN"): trade.tick(self.currentPrice) def showPositions(self): for trade in self.trades: trade.showTrade()
class BotPosition(object): def __init__(self, current_price, start_time, short, takeProfit=0, stopLoss=0): self.output = BotLog() self.status = "OPEN" self.entry_price = current_price self.exit_price = 0. self.start_time = start_time self.exitTime = 0. self.stopLoss = stopLoss self.takeProfit = takeProfit self.short = short if short: self.output.log("OPEN SELL : " + str(self.entry_price)) else: self.output.log("OPEN BUY : " + str(self.entry_price)) def close(self, current_price, endTime): self.status = "CLOSED" self.exit_price = current_price self.exitTime = endTime if self.short: self.output.log("CLOSE BUY : " + str(current_price) + "\n") else: self.output.log("CLOSE SELL : " + str(current_price) + "\n") def tick(self, current_price, candlestick): if self.stopLoss != 0: if self.short and current_price > self.stopLoss: self.close(current_price, candlestick.start_time) return elif not (self.short) and current_price < self.stopLoss: self.close(current_price, candlestick.start_time) return if self.takeProfit != 0: if self.short and current_price < self.takeProfit: self.close(current_price, candlestick.start_time) return elif not (self.short) and current_price > self.takeProfit: self.close(current_price, candlestick.start_time) return def showTrade(self): tradeStatus = "Entry Price: " + str( self.entry_price) + " Status: " + str( self.status) + " Exit Price: " + str(self.exit_price) if (self.status == "CLOSED"): tradeStatus = tradeStatus + " Profit: " if (self.exit_price > self.entry_price): tradeStatus = tradeStatus + "\033[92m" else: tradeStatus = tradeStatus + "\033[91m" tradeStatus = tradeStatus + str(self.exit_price - self.entry_price) + "\033[0m"
class BotTrade(object): def __init__(self,currentPrice,stopLoss=0): self.output = BotLog() self.status = "OPEN" self.entryPrice = currentPrice self.exitPrice = "" self.output.log("Trade opened") if (stopLoss): self.stopLoss = currentPrice - stopLoss #shows closing price def close(self,currentPrice): self.status = "CLOSED" self.exitPrice = currentPrice self.output.log("Trade closed") #shows previous ticks def tick(self, currentPrice): if (self.stopLoss): if (currentPrice < self.stopLoss): self.close(currentPrice)
class BotTrade(object): def __init__(self,currentPrice,stopLoss=0): self.output = BotLog() self.status = "OPEN" self.currentPrice = currentPrice self.entryPrice = currentPrice self.exitPrice = 0 self.output.log("Trade opened") if (stopLoss): self.stopLoss = currentPrice - stopLoss def close(self,currentPrice): self.status = "CLOSED" self.exitPrice = currentPrice self.output.log("Trade closed") #trade_end_time.append(datetime.fromtimestamp(int(time.time())).strftime('%Y-%m-%d %H:%M:%S')) # #total.append(sum(ar_pro)) def tick(self, currentPrice): if (self.stopLoss): if (currentPrice < self.stopLoss): self.close(currentPrice) def showTrade(self): tradeStatus = "Entry Price: "+str(self.entryPrice)+" Status: "+str(self.status)+" Exit Price: "+str(self.exitPrice) if (self.status == "CLOSED"): tradeStatus = tradeStatus + " Profit: " if (self.exitPrice > self.entryPrice): tradeStatus = tradeStatus + "\033[92m" else: tradeStatus = tradeStatus + "\033[91m" tradeStatus = tradeStatus+str(self.exitPrice - self.entryPrice)+"\033[0m" ar_pro.append(self.exitPrice - self.entryPrice) self.output.log(tradeStatus) self.output.log("SubTotal: " + str((sum(ar_pro)))) trade_end_time.append(time.time())#(datetime.fromtimestamp(int(time.time())).strftime('%Y-%m-%d %H:%M:%S')) # total.append(sum(ar_pro)) def export(): filename = open("export.csv",'w') #for i in total: # print('{:.20f}'.format(i[0]) + ',' + str(i[1]) ,file=filename) for i in range(len(trade_end_time)): filename.write("{},{}\n".format(trade_end_time[i],total[i]))
class BotTrade(object): def __init__(self, currentPrice, stopLossEdge): self.output = BotLog() self.status = "OPEN" self.entryPrice = currentPrice self.exitPrice = 0 self.pnl = 0 self.side = "Buy" self.entryTime = datetime.datetime.now() self.exitTime = "" self.output.log("Trade opened") self.stopLoss = currentPrice - stopLossEdge def close(self, currentPrice): self.exitTime = datetime.datetime.now() self.status = "CLOSED" self.side = "Sell" self.exitPrice = currentPrice self.output.log("Trade closed") self.pnl = self.exitPrice - self.entryPrice tradeStatus = "Entry Price: " + str(round(self.entryPrice, 3)) + " Status: " + \ str(self.status) + " Exit Price: " + str(round(self.exitPrice, 3)) tradeStatus = tradeStatus + " Pnl: " + str(round(self.pnl, 3)) if (self.pnl > 0): tradeStatus = crayons.green(tradeStatus) else: tradeStatus = crayons.red(tradeStatus) self.output.log(tradeStatus) def tick(self, currentPrice): if (self.stopLoss > 0): if (currentPrice <= self.stopLoss): self.output.log(crayons.magenta("Exit By Stop Loss")) self.close(currentPrice) def showStatus(self): if (self.status == "OPEN"): tradeStatus = "Entry Price: " + str(round( self.entryPrice, 3)) + " Status: " + str(self.status) tradeStatus = crayons.yellow(tradeStatus) self.output.log(tradeStatus)
class BotTrade(object): def __init__(self, currentPrice, startTime, stopLoss=0): self.output = BotLog() self.status = "OPEN" self.entryPrice = currentPrice self.exitPrice = 0. self.startTime = startTime self.exitTime = 0. self.stopLoss = stopLoss self.output.log("Trade opened: " + str(self.entryPrice) + " StopLoss: " + str(self.stopLoss)) # if (stopLoss): # self.stopLoss = currentPrice - stopLoss def close(self, currentPrice, endTime): self.status = "CLOSED" self.exitPrice = currentPrice self.exitTime = endTime # self.output.log("Trade closed") def tick(self, currentPrice, candlestick): if (self.stopLoss != 0): if (currentPrice < self.entryPrice - self.stopLoss): print("vendu par stopLoss") self.close(currentPrice, candlestick.startTime) def showTrade(self): tradeStatus = "Entry Price: " + str( self.entryPrice) + " Status: " + str( self.status) + " Exit Price: " + str(self.exitPrice) if (self.status == "CLOSED"): tradeStatus = tradeStatus + " Profit: " if (self.exitPrice > self.entryPrice): tradeStatus = tradeStatus + "\033[92m" else: tradeStatus = tradeStatus + "\033[91m" tradeStatus = tradeStatus + str(self.exitPrice - self.entryPrice) + "\033[0m"
class BotTrade(object): def __init__(self, currentPrice, stopLoss=0): self.output = BotLog() self.status = "OPEN" self.entryPrice = currentPrice self.exitPrice = "" self.output.log("Trade opened") if (stopLoss): self.stopLoss = currentPrice - stopLoss def close(self, currentPrice): self.status = "CLOSED" self.exitPrice = currentPrice self.output.log("Trade closed") def tick(self, currentPrice): if (self.stopLoss): if (currentPrice < self.stopLoss): self.close(currentPrice) def showTrade(self): tradeStatus = "Entry Price: " + str( self.entryPrice) + " Status: " + str( self.status) + " Exit Price: " + str(self.exitPrice) if (self.status == "CLOSED"): tradeStatus = tradeStatus + " Profit: " if (self.exitPrice > self.entryPrice): tradeStatus = tradeStatus + "\033[92m" else: tradeStatus = tradeStatus + "\033[91m" tradeStatus = tradeStatus + str(self.exitPrice - self.entryPrice) + "\033[0m" self.output.log(tradeStatus)
class BotChart(object): def __init__(self, functions, pair): self.pair = pair self.output = BotLog() self.conn = functions.poloniex_conn def getHistorical(self, period, startTime, endTime): self.period = period self.startTime = startTime self.endTime = endTime if not os.path.exists("Data/" + self.pair + "_" + str(startTime) + "_" + str(endTime) + "_" + str(self.period) + ".pkl"): self.output.log("Getting chart data (API)...") while True: try: self.data = pd.DataFrame( self.conn.getHistoricTicks(self.pair, self.startTime, self.endTime, self.period)) self.data.to_pickle("Data/" + self.pair + "_" + str(startTime) + "_" + str(endTime) + "_" + str(self.period) + ".pkl") break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue else: self.output.log("Getting chart data (Local)...") self.data = self.__getDataFromFile("Data/" + self.pair + "_" + str(startTime) + "_" + str(endTime) + "_" + str(self.period) + ".pkl") def getPoints(self): return self.data def __getDataFromFile(self, path): return pd.read_pickle(path) def getNext(self): self.output.log("Getting next tick...") return self.conn.getNextTick(self.pair)
def main(argv): pairs = [] try: opts, args = getopt.getopt(argv, "hm:p:c:", ["mode=", "period=", "currency="]) except getopt.GetoptError: print( "bot.py -m <backtest | paper | live> -p <period length in sec> -c <currency pair>" ) sys.exit(2) for opt, arg in opts: if opt == '-h': print( "bot.py -m <backtest | paper | live> -p <period length in sec> -c <currency pair>" ) sys.exit() elif opt in ("-m", "--mode"): if (arg == "backtest"): mode = arg elif (arg == "paper"): mode = arg elif (arg == "live"): mode = arg else: print("Requires mode to be 'backtest', 'paper' or 'live'") sys.exit(2) elif opt in ("-p", "--period"): if (int(arg) in [300, 900, 1800, 7200, 14400, 86400]): period = int(arg) else: print( "Requires periods to be 300, 900, 1800, 7200, 14400, or 86400 second increments" ) sys.exit(2) elif opt in ("-c", "--currency"): pairs.append(arg) start_time = time.time() output = BotLog() exchanges = ["poloniex"] #pairs = ["USDT_BTC", "USDT_ETH", "USDT_LTC", "USDT_ZEC"] #modes = ["RSI"] #modes = ["BBAND"] #modes = ["BBAND", "MACD2", "ALL"] algos = ["MACD"] #modes = ["RSI", "BBAND", "MACD2", "MACD", "DROP", "ALL"] charts = [] strategies = [] target = 0.04 stoploss = 0.18 for pair in pairs: for exchange in exchanges: if (mode == "backtest"): charts.append(BotChart(exchange, pair, period, mode, output)) else: charts.append( BotChart(exchange, pair, period, "warm", output, int(time.time() - (24 * 60 * 60)), int(time.time()))) for algo in algos: if (mode == "backtest"): strategies.append( BotStrategy(exchange + "-" + pair, algo, pair, 1, 5000, 0, int(5000 - 1), stoploss, target, mode, output)) # Parameters: max trades, initial fiat, initial holding, trade amount, stop loss, target else: strategies.append( BotStrategy(exchange + "-" + pair, algo, pair, 1, 5000, 0, int(5000 - 1), stoploss, target, "warm", output)) if (mode == "backtest"): for i, chart in enumerate(charts): for j, algo in enumerate(algos): strategy = strategies[len(algos) * i + j] for candlestick in chart.getPoints(): strategy.tick(candlestick) strategy.showPositions() strategy.showProfit() strategy.drawGraph() output.log("\n--- %s seconds ---" % (time.time() - start_time)) else: candlesticks = [] developingCandlestick = BotCandlestick(output, int(time.time()), period) for i, chart in enumerate(charts): for j, algo in enumerate(algos): strategy = strategies[len(algos) * i + j] for candlestick in chart.getPoints(): strategy.tick(candlestick) strategy.drawGraph() strategy.backtest = mode while True: try: developingCandlestick.tick(chart.getCurrentPrice()) except urllib.error.URLError: time.sleep(int(period / 10)) developingCandlestick.tick(chart.getCurrentPrice()) if (developingCandlestick.isClosed()): candlesticks.append(developingCandlestick) strategy.tick(developingCandlestick) developingCandlestick = BotCandlestick( output, int(time.time()), period) strategy.showPositions() strategy.showProfit() strategy.drawGraph() time.sleep(int(period / 10)) output.close()
class BotStrategy(): def __init__(self, pair): if (not config.CONFIG["VERBOSE"]): print("Calculating indicators") self.pair = pair self.output = BotLog() self.path = config.CONFIG['PATH'] self.prices = [] self.closes = [] self.trades = [] self.movingAVG = [] self.momentum = [] self.RSI = [] self.currentPrice = "" self.currentClose = "" self.numSimulTrades = 1 self.indicators = BotIndicators() self.graph_data = { "date": [], "movingAverage": [], "momentum": [], "RSI": [] } def tick(self, candlestick): self.currentPrice = float(candlestick.priceAverage) self.currentClose = float(candlestick.close) self.movingAVG = self.indicators.movingAverage(self.prices, 15) self.momentum = self.indicators.momentum(self.closes, 15) self.RSI = self.indicators.RSI(self.prices, 15) self.MACD = self.indicators.MACD(self.prices) self.prices.append(self.currentPrice) self.closes.append(self.currentClose) self.output.log("Price: " + str(candlestick.priceAverage) + "\tMoving Average: " + str(self.movingAVG)) self.evaluatePositions(candlestick) self.updateOpenTrades() self.showPositions() def evaluatePositions(self, candlestick): openTrades = [] for trade in self.trades: if (trade.status == "OPEN"): openTrades.append(trade) # Make sure NoneType is handled if (self.movingAVG is None): self.movingAVG = 0 if (len(openTrades) < self.numSimulTrades): if (self.currentPrice < self.movingAVG): self.trades.append(BotTrade(self.currentPrice, stopLoss=.0001)) for trade in openTrades: if (self.currentPrice > self.movingAVG): trade.close(self.currentPrice) self.graph_data['date'].append(candlestick.date.astype(int)) self.graph_data['movingAverage'].append(self.movingAVG) self.graph_data['momentum'].append(self.momentum) self.graph_data['RSI'].append(self.RSI) df = pd.DataFrame(self.graph_data) df.to_csv( util.os.path.join( self.path, 'data/' + self.pair.replace('/', '-') + "/" + 'indicators.csv')) def updateOpenTrades(self): for trade in self.trades: if (trade.status == "OPEN"): trade.tick(self.currentPrice) def showPositions(self): for trade in self.trades: trade.showTrade()
class BotStrategy(object): """ This is the base Strategy object. Any new strategies must extend from this class to inherit key functionality. """ _NAME = NotImplemented def __init__(self, pair, period): self.output = BotLog() self.prices = [] self.trades = [] self.current_price = NotImplemented self.period = period self.num_simultaneous_trades = 3 # Max number of simultaneous trades @classmethod def get_name(cls): return cls._NAME def tick(self, candlestick): raise NotImplementedError def evaluate_positions(self): raise NotImplementedError def update_open_trades(self): for trade in self.trades: if trade.status == "OPEN": trade.tick(self.current_price) def show_positions(self): for trade in self.trades: trade.show_trade() def get_past_prices(self, candle_width, lookback): """Get past close prices :param candle_width Candlestick width in minutes, [1, 5, 15, 30, 60, 240, 1440, 10080, 21600] :param lookback How many past candlesticks to get. """ logger.info("Fetching historical OHLC data for technical indicators...") ohlc = OHLC(pair='XXBTZUSD', interval=candle_width) if not ohlc['error']: past_data = ohlc['result'][self.pair][-lookback:] else: self.output.log(ohlc['error']) return # Make a list of past prices. past_typical_prices = [] # Arithmetic averages of the high, low, and closing prices for a given period. past_open_prices = [] past_close_prices = [] past_high_prices = [] past_low_prices = [] for data in past_data: typical_price = (float(data[2]) + float(data[3]) + float(data[4])) / 3 past_typical_prices.append(typical_price) past_open_prices.append(float(data[1])) past_close_prices.append(float(data[4])) past_high_prices.append(float(data[2])) past_low_prices.append(float(data[3])) return past_typical_prices, past_open_prices, past_close_prices, past_high_prices, past_low_prices
class poloniex_functions(object): def __init__(self): self.output = BotLog() self.conn = Poloniex('secret', 'key') def getBalance(self): while True: try: balData = { k: v for k, v in self.conn.returnBalances().items() if float(v) != 0 } break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return balData def getCurrencies(self): while True: try: tickData = [k for k, v in self.conn.returnTicker().items()] break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return tickData def getNextTick(self, pair): while True: try: tickData = self.conn.returnTicker()[pair] break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return tickData def getHistoricTicks(self, pair, startTime, endTime, period): while True: try: result = self.conn.returnChartData(currencyPair=pair, start=startTime, end=endTime, period=period) break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return result def sell(self, pair, rate, amount): try: result = self.conn.sell(currencyPair=pair, rate=rate, amount=amount) except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) return result def buy(self, pair, rate, amount): try: result = self.conn.buy(currencyPair=pair, rate=rate, amount=amount) except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) return result def returnOrderTrades(self, orderId): while True: try: result = self.conn.returnOrderTrades(orderId) break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return result #============================================================================== # Returns your open orders for a given market, specified by the "currencyPair" POST parameter, # e.g. "BTC_XCP". Set "currencyPair" to "all" to return open orders for all markets. Sample output for single market: #============================================================================== def returnOpenOrders(self, currencyPair='All'): while True: try: result = self.conn.returnOpenOrders(currencyPair) break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return result #============================================================================== # Cancels an order you have placed in a given market. Required POST parameter is "orderNumber". If successful, the method will return: #============================================================================== def cancelOrder(self, orderNumber): while True: try: result = self.conn.cancelOrder(orderNumber) break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return result #============================================================================== # Cancels an order and places a new one of the same type in a single atomic transaction, meaning either both operations will succeed or both will fail. # Required POST parameters are "orderNumber" and "rate"; you may optionally specify "amount" if you wish to change # the amount of the new order. "postOnly" or "immediateOrCancel" may be specified for exchange orders, but will have no effect on margin orders. #============================================================================== def moveOrder(self, orderNumber, rate, amount): while True: try: result = self.conn.moveOrder(orderNumber, rate, amount) break except Exception as e: self.output.log("Error: " + str(e)) time.sleep(20) continue return result
class BotStrategy(object): def __init__(self, backtest=True, forwardtest=True): self.output = BotLog() self.pair = shared.exchange['pair'] self.coinsInOrder = shared.exchange['coinsInOrder'] self.marketInOrder = shared.exchange['marketInOrder'] self.trades = [] self.currentPrice = "" self.currentClose = "" self.lowestAsk = 0.00 self.highestBid = 0.00 self.simultaneousTrades = 4 self.tradeMultiplier = 0.1 self.ticker = {} self.backTest = backtest self.forwardTest = forwardtest self.indicators = BotIndicators() self.candlesticks = [] self.movingAverages = [] self.movingAveragePeriod = shared.strategy['movingAverageLength'] self.trueRanges = [] self.averageTrueRanges = [] # portfolio self.openOrders = [] #api self.api = BotApi() def tick(self, candlestick): #strategy works on closed candles only if not candlestick.isClosed(): return else: self.candlesticks.append(candlestick) self.currentPrice = candlestick.currentPrice ma = self.indicators.sma(self.candlesticks, shared.strategy['movingAverageLength'], 'close') self.movingAverages.append(ma) tr = self.indicators.trueRange(self.candlesticks) self.trueRanges.append(tr) atr = self.indicators.averageTrueRange(self.trueRanges, 5) self.averageTrueRanges.append(atr) self.ticker = self.getTicker(self.pair) portfolioUpdated = self.updatePortfolio() # If live and portfolio not updated, we may run into some unpleasant issues. # Better stop here for now if not portfolioUpdated: return # Strategy needs at least 2 candles to work if len(self.candlesticks) > 1 and candlestick.isClosed(): self.updateOpenTrades(self.pair) self.evaluatePositions() def evaluatePositions(self): openOrders = self.getOpenOrders(self.pair) ''' Go Long (buy) if all of these are met: Previous price is lower movingAverage Current price is higher than moving average Go short (sell) if: Previous price is higher than moving average Current Price is lower than moving average ''' golong1 = self.candlesticks[-2].close < self.movingAverages[-1] golong2 = self.currentPrice > self.movingAverages[-1] goshort1 = self.candlesticks[-2].close > self.movingAverages[-1] goshort2 = self.currentPrice < self.movingAverages[-1] if golong1 and golong2 and len(openOrders) < self.simultaneousTrades: rate = float(self.ticker['lowestAsk']) total = (shared.exchange['nbMarket'] - shared.exchange['marketInOrder']) * self.tradeMultiplier stoploss = self.currentPrice - self.averageTrueRanges[-1] takeprofit = self.currentPrice + (2 * self.averageTrueRanges[-1]) self.buy(rate, total, self.candlesticks[-1].date, stoploss, takeprofit) if goshort1 and goshort2 and len(openOrders) < self.simultaneousTrades: rate = float(self.ticker['highestBid']) amount = (shared.exchange['nbCoin'] - shared.exchange['coinsInOrder']) * self.tradeMultiplier stoploss = self.currentPrice + self.averageTrueRanges[-1] takeprofit = self.currentPrice - (2 * self.averageTrueRanges[-1]) self.sell(rate, amount, self.candlesticks[-1].date, stoploss, takeprofit) def updateOpenTrades(self, pair): openOrders = self.getOpenOrders(pair) # TODO: implement not backtest for trade in openOrders: trade.tick(self.candlesticks[-1], self.candlesticks[-1].date) def getOpenOrders(self, pair): if not self.backTest and not self.forwardTest: orders = self.api.returnOpenOrders(pair) return orders else: openOrders = [] for order in self.trades: if order.status == 'OPEN': openOrders.append(order) return openOrders def getCurrentPrice(self, pair): if not self.backTest: return self.api.returnTicker(pair)['last'] else: return self.candlesticks[-1].close def getTicker(self, pair): if not self.backTest: return self.api.returnTicker(pair) else: return { 'last': self.currentPrice, 'highestBid': self.currentPrice - self.currentPrice * shared.exchange['spreadPercentage'], 'lowestAsk': self.currentPrice + self.currentPrice * shared.exchange['spreadPercentage'] } def updatePortfolio(self): if not self.backTest and not self.forwardTest: try: portfolio = self.api.returnBalances() if shared.exchange['market'] in portfolio: shared.exchange['nbMarket'] = float( portfolio[shared.exchange['market']]) else: shared.exchange['nbMarket'] = 0.00 if shared.exchange['coin'] in portfolio: shared.exchange['nbCoin'] = float( portfolio[shared.exchange['coin']]) else: shared.exchange['nbCoin'] = 0.00 return True except Exception as e: self.output.warning("Error updating portfolio") print(e) return False else: return True def showPortfolio(self): if not self.backTest and not self.forwardTest: self.updatePortfolio() self.output.log( str(shared.exchange['nbMarket']) + " " + str(shared.exchange['market']) + ' - ' + str(shared.exchange['nbCoin']) + " " + str(shared.exchange['coin'])) def buy(self, rate, total, date, stopLoss=0, takeProfit=0): amount = total / rate order = BotTrade('BUY', rate=rate, amount=amount, total=total, date=date, stopLoss=stopLoss, takeProfit=takeProfit, backtest=self.backTest, forwardtest=self.forwardTest) self.trades.append(order) def sell(self, rate, amount, date, stopLoss=0, takeProfit=0): total = rate * amount order = BotTrade('SELL', rate=rate, amount=amount, total=total, date=date, stopLoss=stopLoss, takeProfit=takeProfit, backtest=self.backTest, forwardtest=self.forwardTest) self.trades.append(order)
class Trading_Gui: def __init__(self, top=None): '''This class configures and populates the toplevel window. top is the toplevel containing window.''' _bgcolor = '#d9d9d9' # X11 color: 'gray85' _fgcolor = '#000000' # X11 color: 'black' _compcolor = '#d9d9d9' # X11 color: 'gray85' _ana1color = '#d9d9d9' # X11 color: 'gray85' _ana2color = '#d9d9d9' # X11 color: 'gray85' self.root = root self.style = ttk.Style() self.style.theme_use("vista") self.style.configure('.',background=_bgcolor) self.style.configure('.',foreground=_fgcolor) self.style.configure('.',font="TkDefaultFont") self.style.map('.',background= [('selected', _compcolor), ('active',_ana2color)]) self.strategy= [] self.showChart = False self.startTrading = False self.closeAll= False self.stopRunning= False self.numberOfExecutions= 0 self.numberOfTrades = 0 self.output = BotLog() self.liveChartObject= [] self.CheckVar = IntVar() top.geometry("990x518+446+155") top.title("Trading Gui") top.configure(background="#d9d9d9") self.TFrame1 = ttk.Frame(top) self.TFrame1.place(relx=0.01, rely=0.02, relheight=0.98, relwidth=0.11) self.TFrame1.configure(relief=GROOVE) self.TFrame1.configure(borderwidth="2") self.TFrame1.configure(relief=GROOVE) self.TFrame1.configure(width=95) self.Run = ttk.Button(self.TFrame1, command=self.main) self.Run.place(relx=0.11, rely=0.07, height=35, width=76) self.Run.configure(takefocus="") self.Run.configure(text='''Run''') self.Run.configure(width=76) self.Stop = ttk.Button(self.TFrame1, command=self.stopRun) self.Stop.place(relx=0.11, rely=0.17, height=35, width=76) self.Stop.configure(takefocus="") self.Stop.configure(text='''Stop''') self.Stop.configure(width=76) self.StartTrade = ttk.Button(self.TFrame1, command= self.useStartegy) self.StartTrade.place(relx=0.11, rely=0.27, height=35, width=76) self.StartTrade.configure(takefocus="") self.StartTrade.configure(text='''StartTrade''') self.StartTrade.configure(width=76) self.StopTrade = ttk.Button(self.TFrame1, command=self.stopTrade) self.StopTrade.place(relx=0.11, rely=0.37, height=35, width=76) self.StopTrade.configure(takefocus="") self.StopTrade.configure(text='''StopTrade''') self.StopTrade.configure(width=76) self.ShowChart = ttk.Button(self.TFrame1, command= self.chartOpen) self.ShowChart.place(relx=0.11, rely=0.47, height=35, width=76) self.ShowChart.configure(takefocus="") self.ShowChart.configure(text='''ShowChart''') self.ShowChart.configure(width=76) self.CloseChart = ttk.Button(self.TFrame1, command= self.chartClose) self.CloseChart.place(relx=0.11, rely=0.57, height=35, width=76) self.CloseChart.configure(takefocus="") self.CloseChart.configure(text='''CloseChart''') self.CloseChart.configure(width=76) self.ClosePos = ttk.Button(self.TFrame1, command= self.closeAllPositions) self.ClosePos.place(relx=0.11, rely=0.67, height=35, width=76) self.ClosePos.configure(takefocus="") self.ClosePos.configure(text='''ClosePos''') self.CheckVar.set(1) self.SaveTrades = Checkbutton(self.TFrame1, text="SaveHistory", variable=self.CheckVar, bg=_bgcolor) self.SaveTrades.place(relx=0.11, rely=0.77, height=35, width=80) self.Exit = ttk.Button(self.TFrame1, command= self.CloseWindow) self.Exit.place(relx=0.11, rely=0.9, height=35, width=76) self.Exit.configure(takefocus="") self.Exit.configure(text='''Exit''') self.Exit.configure(width=76) self.TFrame3 = Frame(top) self.TFrame3.place(relx=0.15, rely=0.05, relheight=0.1, relwidth=0.8) self.TFrame3.configure(relief=GROOVE) self.TFrame3.configure(borderwidth="2") self.TFrame3.configure(relief=GROOVE) self.TFrame3.configure(width=475) self.TFrame3.configure(takefocus="0") self.TLabel5 = Label(self.TFrame3) self.TLabel5.place(relx=0.01, rely=0.18, height=19, width=55) self.TLabel5.configure(font=('Helvetica', 8)) self.TLabel5.configure(foreground="#075bb8") self.TLabel5.configure(relief=FLAT) self.TLabel5.configure(text='''Ticker:''') self.ticker = Entry(self.TFrame3) self.ticker.insert(END, str("USDT_BTC")) self.ticker.place(relx=0.07, rely=0.18, relheight=0.44, relwidth=0.09) self.ticker.configure(font=('Helvetica', 10)) self.ticker.configure(background="white") self.ticker.configure(font="TkTextFont") self.ticker.configure(foreground="black") self.ticker.configure(highlightbackground="#d9d9d9") self.ticker.configure(highlightcolor="black") self.ticker.configure(insertbackground="black") self.ticker.configure(selectbackground="#c4c4c4") self.ticker.configure(selectforeground="black") self.ticker.configure(takefocus="0") self.TLabel4 = Label(self.TFrame3) self.TLabel4.place(relx=0.18, rely=0.18, height=19, width=75) self.TLabel4.configure(font=('Helvetica', 8)) self.TLabel4.configure(foreground="#075bb8") self.TLabel4.configure(relief=FLAT) self.TLabel4.configure(text='''StopLossEdge:''') self.StopLossEdge = Entry(self.TFrame3) self.StopLossEdge.insert(END, str(10)) self.StopLossEdge.place(relx=0.28, rely=0.18, relheight=0.44, relwidth=0.09) self.StopLossEdge.configure(font=('Helvetica', 10)) self.StopLossEdge.configure(background="white") self.StopLossEdge.configure(font="TkTextFont") self.StopLossEdge.configure(foreground="black") self.StopLossEdge.configure(highlightbackground="#d9d9d9") self.StopLossEdge.configure(highlightcolor="black") self.StopLossEdge.configure(insertbackground="black") self.StopLossEdge.configure(selectbackground="#c4c4c4") self.StopLossEdge.configure(selectforeground="black") self.StopLossEdge.configure(takefocus="0") self.TLabel5 = Label(self.TFrame3) self.TLabel5.place(relx=0.39, rely=0.2, height=19, width=65) self.TLabel5.configure(font=('Helvetica', 8)) self.TLabel5.configure(foreground="#075bb8") self.TLabel5.configure(relief=FLAT) self.TLabel5.configure(takefocus="0") self.TLabel5.configure(text='''EntryEdge:''') self.EntryEdge = Entry(self.TFrame3) self.EntryEdge.insert(END, str(1)) self.EntryEdge.place(relx=0.47, rely=0.15, relheight=0.44, relwidth=0.09) self.EntryEdge.configure(background="white") self.EntryEdge.configure(font="TkTextFont") self.EntryEdge.configure(foreground="black") self.EntryEdge.configure(highlightbackground="#d9d9d9") self.EntryEdge.configure(highlightcolor="black") self.EntryEdge.configure(insertbackground="black") self.EntryEdge.configure(selectbackground="#c4c4c4") self.EntryEdge.configure(selectforeground="black") self.EntryEdge.configure(takefocus="0") self.TLabel6 = Label(self.TFrame3) self.TLabel6.place(relx=0.58, rely=0.2, height=19, width=85) self.TLabel6.configure(font=('Helvetica', 8)) self.TLabel6.configure(foreground="#075bb8") self.TLabel6.configure(relief=FLAT) self.TLabel6.configure(takefocus="0") self.TLabel6.configure(text='''OpenTradesLimit:''') self.OpenTradesLimit = Entry(self.TFrame3) self.OpenTradesLimit.insert(END, str(4)) self.OpenTradesLimit.place(relx=0.69, rely=0.15, relheight=0.44, relwidth=0.09) self.OpenTradesLimit.configure(background="white") self.OpenTradesLimit.configure(font="TkTextFont") self.OpenTradesLimit.configure(foreground="black") self.OpenTradesLimit.configure(highlightbackground="#d9d9d9") self.OpenTradesLimit.configure(highlightcolor="black") self.OpenTradesLimit.configure(insertbackground="black") self.OpenTradesLimit.configure(selectbackground="#c4c4c4") self.OpenTradesLimit.configure(selectforeground="black") self.OpenTradesLimit.configure(takefocus="0") self.TLabel7 = Label(self.TFrame3) self.TLabel7.place(relx=0.79, rely=0.2, height=19, width=85) self.TLabel7.configure(font=('Helvetica', 8)) self.TLabel7.configure(foreground="#075bb8") self.TLabel7.configure(relief=FLAT) self.TLabel7.configure(takefocus="0") self.TLabel7.configure(text='''Maintenance:''') self.Maintenance = Entry(self.TFrame3) self.Maintenance.insert(END, str(1)) self.Maintenance.place(relx=0.89, rely=0.15, relheight=0.44, relwidth=0.09) self.Maintenance.configure(background="white") self.Maintenance.configure(font="TkTextFont") self.Maintenance.configure(foreground="black") self.Maintenance.configure(highlightbackground="#d9d9d9") self.Maintenance.configure(highlightcolor="black") self.Maintenance.configure(insertbackground="black") self.Maintenance.configure(selectbackground="#c4c4c4") self.Maintenance.configure(selectforeground="black") self.Maintenance.configure(takefocus="0") self.style.configure('Treeview.Heading', font="TkDefaultFont") self.Scrolledtreeview1 = ScrolledTreeView(top) self.Scrolledtreeview1.place(relx=0.15, rely=0.23, relheight=0.28, relwidth=0.6) self.Scrolledtreeview1.configure(columns="Col1 Col2 Col3 Col4 Col5") self.Scrolledtreeview1.configure(takefocus="0") self.Scrolledtreeview1.heading("#0",text="Id") self.Scrolledtreeview1.heading("#0",anchor="center") self.Scrolledtreeview1.column("#0",width="35") self.Scrolledtreeview1.column("#0",minwidth="20") self.Scrolledtreeview1.column("#0",stretch="1") self.Scrolledtreeview1.column("#0",anchor="w") self.Scrolledtreeview1.heading("Col1",text="Time") self.Scrolledtreeview1.heading("Col1",anchor="center") self.Scrolledtreeview1.column("Col1",width="150") self.Scrolledtreeview1.column("Col1",minwidth="20") self.Scrolledtreeview1.column("Col1",stretch="1") self.Scrolledtreeview1.column("Col1",anchor="w") self.Scrolledtreeview1.heading("Col2",text="Symbol") self.Scrolledtreeview1.heading("Col2",anchor="center") self.Scrolledtreeview1.column("Col2",width="80") self.Scrolledtreeview1.column("Col2",minwidth="20") self.Scrolledtreeview1.column("Col2",stretch="1") self.Scrolledtreeview1.column("Col2",anchor="w") self.Scrolledtreeview1.heading("Col3",text="Side") self.Scrolledtreeview1.heading("Col3",anchor="center") self.Scrolledtreeview1.column("Col3",width="80") self.Scrolledtreeview1.column("Col3",minwidth="20") self.Scrolledtreeview1.column("Col3",stretch="1") self.Scrolledtreeview1.column("Col3",anchor="w") self.Scrolledtreeview1.heading("Col4",text="Price") self.Scrolledtreeview1.heading("Col4",anchor="center") self.Scrolledtreeview1.column("Col4",width="80") self.Scrolledtreeview1.column("Col4",minwidth="20") self.Scrolledtreeview1.column("Col4",stretch="1") self.Scrolledtreeview1.column("Col4",anchor="w") self.Scrolledtreeview1.heading("Col5",text="Pnl") self.Scrolledtreeview1.heading("Col5",anchor="center") self.Scrolledtreeview1.column("Col5",width="80") self.Scrolledtreeview1.column("Col5",minwidth="20") self.Scrolledtreeview1.column("Col5",stretch="1") self.Scrolledtreeview1.column("Col5",anchor="w") self.menubar = Menu(top,font="TkMenuFont",bg='#bef7bb',fg=_fgcolor) top.configure(menu = self.menubar) self.Scrolledtreeview2 = ScrolledTreeView(top) self.style.configure("Scrolledtreeview2", font='helvetica 24') self.Scrolledtreeview2.place(relx=0.15, rely=0.61, relheight=0.32, relwidth=0.8) self.Scrolledtreeview2.configure(columns="Col1 Col2 Col3 Col4 Col5 Col6 Col7") self.Scrolledtreeview2.configure(takefocus="0") self.Scrolledtreeview2.heading("#0", text="Id") self.Scrolledtreeview2.heading("#0", anchor="center") self.Scrolledtreeview2.column("#0", width="35") self.Scrolledtreeview2.column("#0", minwidth="20") self.Scrolledtreeview2.column("#0", stretch="1") self.Scrolledtreeview2.column("#0", anchor="w") self.Scrolledtreeview2.heading("Col1", text="EntryTime") self.Scrolledtreeview2.heading("Col1", anchor="center") self.Scrolledtreeview2.column("Col1", width="150") self.Scrolledtreeview2.column("Col1", minwidth="20") self.Scrolledtreeview2.column("Col1", stretch="1") self.Scrolledtreeview2.column("Col1", anchor="w") self.Scrolledtreeview2.heading("Col2", text="ExitTime") self.Scrolledtreeview2.heading("Col2", anchor="center") self.Scrolledtreeview2.column("Col2", width="150") self.Scrolledtreeview2.column("Col2", minwidth="20") self.Scrolledtreeview2.column("Col2", stretch="1") self.Scrolledtreeview2.column("Col2", anchor="w") self.Scrolledtreeview2.heading("Col3", text="Symbol") self.Scrolledtreeview2.heading("Col3", anchor="center") self.Scrolledtreeview2.column("Col3", width="81") self.Scrolledtreeview2.column("Col3", minwidth="20") self.Scrolledtreeview2.column("Col3", stretch="1") self.Scrolledtreeview2.column("Col3", anchor="w") self.Scrolledtreeview2.heading("Col4", text="Side") self.Scrolledtreeview2.heading("Col4", anchor="center") self.Scrolledtreeview2.column("Col4", width="80") self.Scrolledtreeview2.column("Col4", minwidth="20") self.Scrolledtreeview2.column("Col4", stretch="1") self.Scrolledtreeview2.column("Col4", anchor="w") self.Scrolledtreeview2.heading("Col5", text="EntryPrice") self.Scrolledtreeview2.heading("Col5", anchor="center") self.Scrolledtreeview2.column("Col5", width="80") self.Scrolledtreeview2.column("Col5", minwidth="20") self.Scrolledtreeview2.column("Col5", stretch="1") self.Scrolledtreeview2.column("Col5", anchor="w") self.Scrolledtreeview2.heading("Col6", text="ExitPrice") self.Scrolledtreeview2.heading("Col6", anchor="center") self.Scrolledtreeview2.column("Col6", width="80") self.Scrolledtreeview2.column("Col6", minwidth="20") self.Scrolledtreeview2.column("Col6", stretch="1") self.Scrolledtreeview2.column("Col6", anchor="w") self.Scrolledtreeview2.heading("Col7", text="Pnl") self.Scrolledtreeview2.heading("Col7", anchor="center") self.Scrolledtreeview2.column("Col7", width="80") self.Scrolledtreeview2.column("Col7", minwidth="20") self.Scrolledtreeview2.column("Col7", stretch="1") self.Scrolledtreeview2.column("Col7", anchor="w") self.Label1 = Label(top) self.Label1.place(relx=0.15, rely=0.17, height=25, width=595) self.Label1.configure(font=('Helvetica', 10)) self.Label1.configure(anchor=N) self.Label1.configure(background="#b4c2fe") self.Label1.configure(compound="left") self.Label1.configure(cursor="bottom_left_corner") self.Label1.configure(disabledforeground="#a3a3a3") self.Label1.configure(foreground="#000000") self.Label1.configure(justify=LEFT) self.Label1.configure(relief=RIDGE) self.Label1.configure(text='''Opened Positions''') self.Label1.configure(textvariable=test_support) self.Label1.configure(width=459) self.Label2 = Label(top) self.Label2.place(relx=0.15, rely=0.55, height=25, width=788) self.Label2.configure(font=('Helvetica', 10)) self.Label2.configure(activebackground="#f9f9f9") self.Label2.configure(activeforeground="black") self.Label2.configure(anchor=N) self.Label2.configure(background="#b4c2fe") self.Label2.configure(compound="left") self.Label2.configure(cursor="bottom_left_corner") self.Label2.configure(disabledforeground="#a3a3a3") self.Label2.configure(foreground="#000000") self.Label2.configure(highlightbackground="#d9d9d9") self.Label2.configure(highlightcolor="black") self.Label2.configure(justify=LEFT) self.Label2.configure(relief=RIDGE) self.Label2.configure(text='''Trades''') self.Label2.configure(width=459) self.TFrame2 = Frame(top) self.TFrame2.place(relx=0.76, rely=0.23, relheight=0.22, relwidth=0.2) self.TFrame2.configure(relief=SUNKEN) self.TFrame2.configure(borderwidth="2") self.TFrame2.configure(relief=SUNKEN) self.TFrame2.configure(width=150) self.TFrame2.configure(takefocus="0") self.TotalPnl = Label(self.TFrame2) self.TotalPnl.place(relx=0.002, rely=0.17, height=29, width=86) self.TotalPnl.configure(font=('Helvetica', 11)) self.TotalPnl.configure(foreground="#075bb8") self.TotalPnl.configure(relief=FLAT) self.TotalPnl.configure(justify=RIGHT) self.TotalPnl.configure(takefocus="0") self.TotalPnl.configure(text='''TotalPnl:''') self.TradesCount = Label(self.TFrame2) self.TradesCount.place(relx=0.01, rely=0.63, height=29, width=106) self.TradesCount.configure(font=('Helvetica', 11)) self.TradesCount.configure(foreground="#075bb8") self.TradesCount.configure(relief=FLAT) self.TradesCount.configure(justify=RIGHT) self.TradesCount.configure(takefocus="0") self.TradesCount.configure(text='''TradesCount:''') self.tradesCount = Text(self.TFrame2) self.tradesCount.configure(font=('Helvetica', 10)) self.tradesCount.place(relx=0.52, rely=0.6, relheight=0.3, relwidth=0.4) self.tradesCount.configure(font=('Helvetica', 10)) self.tradesCount.configure(background="white") self.tradesCount.configure(font="TkTextFont") self.tradesCount.configure(foreground="black") self.tradesCount.configure(highlightbackground="#d9d9d9") self.tradesCount.configure(highlightcolor="black") self.tradesCount.configure(insertbackground="black") self.tradesCount.configure(selectbackground="#c4c4c4") self.tradesCount.configure(selectforeground="black") self.tradesCount.configure(takefocus="0") self.tradesCount.configure(width=104) self.totalPnl = Text(self.TFrame2, font= ('Times', '24', 'bold italic') ) self.totalPnl.place(relx=0.52, rely=0.1, relheight=0.3, relwidth=0.4) self.totalPnl.configure(font=('Helvetica', 10)) self.totalPnl.configure(background="white") self.totalPnl.configure(font="TkTextFont") self.totalPnl.configure(foreground="black") self.totalPnl.configure(highlightbackground="#d9d9d9") self.totalPnl.configure(highlightcolor="black") self.totalPnl.configure(insertbackground="black") self.totalPnl.configure(selectbackground="#c4c4c4") self.totalPnl.configure(selectforeground="black") self.totalPnl.configure(takefocus="0") self.totalPnl.configure(width=104) def stopRun(self): self.root.update() self.stopRunning= True self.output.log(crayons.red("System stop..........")) def CloseWindow(self) : self.root.destroy() def chartOpen(self) : self.liveChartObject = botChart() self.root.update() self.showChart= True def chartClose(self) : self.root.update() self.showChart= False plt.close() def useStartegy(self) : self.root.update() self.startTrading= True self.stopRunning= False self.output.log(crayons.green("Start trading..........")) def stopTrade(self) : self.root.update() try: opPos= self.strategy.openedPositions except: opPos= [] if len(opPos)>0: messagebox.showinfo("Warning", "There are opened position. Close all before stopping trading!") else: self.startTrading = False self.output.log(crayons.green("End trading..........")) def closeAllPositions(self) : self.root.update() self.closeAll = True def insertDataExecutions(self, executions): n= len(executions) if n>self.numberOfExecutions: newExecutions= executions[-(n-self.numberOfExecutions):] k= n for row in newExecutions: self.Scrolledtreeview1.insert('', 'end', text=str(k),\ values=( str(row[0]).split(" ")[-1], row[1], row[3], round(row[2],2), round(row[4],3))) k= k+1 self.numberOfExecutions= n def insertDataTrades(self, trades): n= len(trades) if n>self.numberOfTrades: newTrades= trades[-(n-self.numberOfTrades):] k= self.numberOfTrades for row in newTrades: self.Scrolledtreeview2.insert('', 'end', text=str(k),\ values=( str(row[0]).split(" ")[-1], str(row[1]).split(" ")[-1], row[2], \ row[5], round(row[3],2), round(row[4],2), round(row[6],3))) k= k+1 self.numberOfTrades= n def insertOpenData(self, openedPositions): self.Scrolledtreeview1.delete(*self.Scrolledtreeview1.get_children()) for i,row in enumerate(openedPositions): self.Scrolledtreeview1.insert('', 'end', text=str(i),\ values=( str(row[0]).split(" ")[-1], row[1], \ row[2], round(row[3], 2), round(row[4], 2)), tags=('new')) def saveTradeHistory(self, strategy): if self.CheckVar: data= strategy.showExecutions() if len(data)>0: data.to_csv("TradingHistory.csv", index=False) else: with open("TradingHistory.csv", 'w'): pass def main(self): period = 10 pair = "USDT_BTC" lengthMA = 50 error=False self.stopRunning= False self.numberOfTrades= 0 try: data = BotGetData(pair, period) historical = data.historicalData except Exception as e: historical = [] messagebox.showinfo("Error", e) error= True try: stopLossEdge= float(self.StopLossEdge.get()) except: messagebox.showinfo("Error", "Wrong StopLoss input. Must be integer.") error= True try: entryEdge= float(self.EntryEdge.get()) entryEdge= 0 except: messagebox.showinfo("Error", "Wrong StopLoss input. Must be numeric.") error= True try: openPosLimit= int(self.OpenTradesLimit.get()) if openPosLimit<=0: messagebox.showinfo("Error", "Wrong openPosLimit input. Must be integer>0.") openPosLimit= 1 except: messagebox.showinfo("Error", "Wrong openPosLimit input. Must be integer.") error= True try: timePosEdge= int(self.Maintenance.get()) if timePosEdge<0: messagebox.showinfo("Error", "Wrong Maintenance input. Must be integer>=0.") timePosEdge= 1 except: messagebox.showinfo("Error", "Wrong Maintenance input. Must be integer.") error= True if not error: prices = historical.Price.tolist() if (len(historical) > lengthMA): prices = prices[-lengthMA:] else: print("Not enough historical data for MA=" + str(lengthMA)) lengthMA = len(prices) self.strategy = BotStrategy(prices=prices, pair=pair, lengthMA=lengthMA, \ openPosLimit=openPosLimit, stopLossEdge=stopLossEdge, \ entryEdge=entryEdge, timePosEdge=timePosEdge) while True: try: if self.stopRunning: self.startTrading = False self.saveTradeHistory(strategy=self.strategy) self.Scrolledtreeview1.delete(*self.Scrolledtreeview1.get_children()) self.Scrolledtreeview2.delete(*self.Scrolledtreeview2.get_children()) self.strategy.closeAll() self.strategy.clearExecutions() break data.updateData() lastPairPrice = data.lastPrice prices.append(lastPairPrice) prices = prices[-lengthMA:] self.strategy.tick(lastPairPrice, self.startTrading) executions = self.strategy.allExecutions.execData trades = self.strategy.allTrades.tradesData histDataUpdated = chartHorizon(histDataUpdated=data.historicalData, interval=15) openedPositions= self.strategy.openedPositions self.insertDataTrades(trades) self.insertOpenData(openedPositions) self.tradesCount.delete(1.0, END) self.tradesCount.insert(END, str(len(trades))) self.totalPnl.delete(1.0, END) self.totalPnl.insert(END, str(round(self.strategy.totalPnl,1))) if self.closeAll: self.strategy.closeAll() self.saveTradeHistory(strategy=self.strategy) if self.showChart: self.liveChartObject.botLiveChart(x=histDataUpdated.Date, y=histDataUpdated.Price, \ tradesLive=executions, lastTradePnl=self.strategy.lastTradePnl, \ totalPnl=self.strategy.totalPnl, percentChange=data.percentChange) self.root.update() except Exception as e: messagebox.showinfo("Error", str(e)) self.strategy.closeAll() self.saveTradeHistory(strategy=self.strategy) break
class BotStrategy(object): def __init__(self): self.output = BotLog() self.prices = [] self.currentPrice = "" self.indicators = BotIndicators() self.GRC_bal = False self.BTC_bal = False self.Total_bal = False self.can_buy = False self.can_sell = False self.trade_amount = .00059 # BTC self.to_buy = False self.to_sell = False self.pair = 'BTC_GRC' self.order_num = False self.orders = [] self.high_bid_price = False self.low_ask_price = False self.low_ask_amount = False self.high_bid_amount = False self.price_to_buy = False self.price_to_sell = False self.openTrades = [] self.open_Bids = [] self.open_Asks = [] self.orders = [] self.last_sell_price = False self.last_buy_price = False self.open_sell_flag = False self.open_buy_flag = False self.raw_spread = 0 self.mod_spread = 0 self.place_orders_flag = True def tick(self, candlestick): print('') print('############## Gridcoin data ###############') self.currentPrice = float(candlestick.priceAverage) self.prices.append(self.currentPrice) print("Price: " + str(candlestick.priceAverage)) self.set_order_prices() self.updateOpenTrades() self.evaluatePositions_Market_Make() print('############## End Gridcoin data ###############') def evaluatePositions_Market_Make(self): # Have to re-check balances after possibly cancelling orders self.balance = polo.returnBalances() self.GRC_bal = float(self.balance['GRC']) self.BTC_bal = float(self.balance['BTC']) self.Total_bal = self.GRC_bal + (self.BTC_bal / float(self.currentPrice)) if self.place_orders_flag == True: # Current code uses a BTC constant for trade amount, defined above if self.open_buy_flag == False: # self.can_buy = self.BTC_bal / self.price_to_buy if self.BTC_bal > 0.95 * self.trade_amount: #extra padding was to allow for FLDC trading if self.BTC_bal > self.trade_amount: self.to_buy = self.trade_amount / self.price_to_buy else: self.to_buy = self.BTC_bal * 0.99 / self.price_to_buy val_check = "Value check " + self.pair + " " + "{:.8f}".format( self.price_to_buy) + " " + "{:.8f}".format(self.to_buy) print(val_check) placed_order = polo.buy(self.pair, "{:.8f}".format(self.price_to_buy), "{:.8f}".format(self.to_buy)) print("Buy order placed!") print(placed_order) if self.open_sell_flag == False: if self.GRC_bal > self.trade_amount / self.price_to_sell * 0.95: if self.GRC_bal > self.trade_amount / self.price_to_sell: self.to_sell = self.trade_amount / self.price_to_sell else: self.to_sell = self.GRC_bal * 0.99 val_check = "Value check " + self.pair + " " + "{:.8f}".format( self.price_to_sell) + " " + "{:.8f}".format( self.to_sell) print(val_check) placed_order = polo.sell( self.pair, "{:.8f}".format(self.price_to_sell), "{:.8f}".format(self.to_sell)) print("Sell order placed!") print(placed_order) # Code for trading with a GRC constant # if self.place_orders_flag == True: # # if self.open_buy_flag == False: # self.can_buy = self.BTC_bal / self.price_to_buy # if self.can_buy > 90: # if self.can_buy > 100: # self.to_buy = 100 # else: # self.to_buy = self.can_buy - 1 # val_check = "Value check " + self.pair + " " + "{:.8f}".format(self.price_to_buy) + " " + "{:.8f}".format(self.to_buy) # print(val_check) # placed_order = polo.buy(self.pair, "{:.8f}".format(self.price_to_buy), "{:.8f}".format(self.to_buy)) # print("Buy order placed!") # print(placed_order) # # if self.open_sell_flag == False and self.GRC_bal > 90: # if self.GRC_bal > 100: # self.to_sell = 100 # else: # self.to_sell = self.GRC_bal - 1 # val_check = "Value check " + self.pair + " " + "{:.8f}".format(self.price_to_sell) + " " + "{:.8f}".format(self.to_sell) # print(val_check) # placed_order = polo.sell(self.pair, "{:.8f}".format(self.price_to_sell), "{:.8f}".format(self.to_sell)) # print("Sell order placed!") # print(placed_order) # def Order_book(self, pair): # self.orders = polo.returnOrderBook(pair, 5) # self.high_bid_price = float(self.orders['bids'][0][0]) # self.high_bid_amount = float(self.orders['bids'][0][1]) # self.low_ask_price = float(self.orders['asks'][0][0]) # self.low_ask_amount = float(self.orders['asks'][0][1]) def updateOpenTrades(self): print('BEFORE trade update the flags were:') print('Place orders flag = ' + str(self.place_orders_flag)) print('Open buy flag = ' + str(self.open_buy_flag)) print('Open sell flag = ' + str(self.open_sell_flag)) self.openTrades = polo.returnOpenOrders(self.pair) self.open_Bids = [] self.open_Asks = [] if len(self.openTrades) == 0: self.open_buy_flag = False self.open_sell_flag = False print('Open trade flags set to False because openTrades was empty') elif len(self.openTrades) > 0: for trade in self.openTrades: order_Type = trade['type'] order_Num = trade['orderNumber'] if order_Type == 'buy': self.open_Bids.append(order_Num) elif order_Type == 'sell': self.open_Asks.append(order_Num) if len(self.open_Bids) == 0: self.open_buy_flag = False print( 'Open buy flag set to false because openTrades > 0 and no bids' ) if len(self.open_Asks) == 0: self.open_sell_flag = False print( 'Open sell flag set to false because openTrades > 0 and no asks' ) # Originally was outside the above if block # for trade in self.openTrades: # order_Type = trade['type'] # order_Num = trade['orderNumber'] # if order_Type == 'buy': # self.open_Bids.append(order_Num) # elif order_Type == 'sell': # self.open_Asks.append(order_Num) # # if len(self.open_Bids) == 0: # self.open_buy_flag = False # if len(self.open_Asks) == 0: # self.open_sell_flag = False if len(self.openTrades) > 0: print('openTrades was not empty so trades were checked') self.output.log(self.openTrades) if self.place_orders_flag == False: for trade in self.openTrades: order_Num = trade['orderNumber'] polo.cancelOrder(order_Num) print('Spread too small, all orders cancelled') elif self.place_orders_flag == True: for trade in self.openTrades: order_Num = trade['orderNumber'] order_Type = trade['type'] order_price = float(trade['rate']) if order_Type == "buy": if order_price == self.price_to_buy: self.open_buy_flag = True print( "Previous buy order still open at target price" ) print( 'Open buy flag set to True because previous order exists' ) elif order_price != self.price_to_buy: polo.cancelOrder(order_Num) print("Buy order closed") self.open_buy_flag = False print( 'Open buy flag set to False due to cancelled trade' ) elif order_Type == "sell": if order_price == self.price_to_sell: self.open_sell_flag = True print( "Previous sell order still open at target price." ) print( 'Open sell flag set to True because previous order exists' ) elif order_price != self.price_to_sell: polo.cancelOrder(order_Num) print("Sell order closed") self.open_sell_flag = False print( 'Open sell flag set to False due to cancelled trade' ) self.openTrades = polo.returnOpenOrders(self.pair) print('AFTER trade update the flags were:') print('Place orders flag = ' + str(self.place_orders_flag)) print('Open buy flag = ' + str(self.open_buy_flag)) print('Open sell flag = ' + str(self.open_sell_flag)) def set_order_prices(self): self.balance = polo.returnBalances() self.GRC_bal = float(self.balance['GRC']) self.BTC_bal = float(self.balance['BTC']) self.Total_bal = self.GRC_bal + (self.BTC_bal / float(self.currentPrice)) self.orders = polo.returnOrderBook(self.pair, 5) self.high_bid_price = float(self.orders['bids'][0][0]) self.high_bid_amount = float(self.orders['bids'][0][1]) self.low_ask_price = float(self.orders['asks'][0][0]) self.low_ask_amount = float(self.orders['asks'][0][1]) self.output.log("High bid: " + str(self.high_bid_price) + " Low ask: " + str(self.low_ask_price)) self.raw_spread = self.low_ask_price - self.high_bid_price print('Raw spread = ' + str(self.raw_spread)) if self.raw_spread >= 7E-8: if self.high_bid_amount > 100: self.price_to_buy = self.high_bid_price + 1E-8 else: self.price_to_buy = self.high_bid_price if self.low_ask_amount > 100: self.price_to_sell = self.low_ask_price - 1E-8 else: self.price_to_sell = self.low_ask_price self.place_orders_flag = True elif self.raw_spread < 7E-8: orders = self.orders bids = [] for x in orders['bids']: bid_price = x[0] bid_amount = x[1] bids.append([bid_price, bid_amount]) bids_running_sum = 0 bids_index_counter = 0 for y in bids: bids_running_sum += float(y[1]) if bids_running_sum > 1000 and bids_index_counter == 0: buy_price_index = 0 overcut = True break elif bids_running_sum > 1000 and bids_index_counter > 0: buy_price_index = bids_index_counter - 1 overcut = False break else: buy_price_index = bids_index_counter overcut = False bids_index_counter += 1 if overcut == True: self.price_to_buy = self.high_bid_price + 1E-8 print('Overcutting') else: print('Buy at index: ' + str(buy_price_index)) price_to_buy_txt = str(bids[buy_price_index][0]) self.price_to_buy = float(price_to_buy_txt) asks = [] for x in orders['asks']: ask_price = x[0] ask_amount = x[1] asks.append([ask_price, ask_amount]) asks_running_sum = 0 asks_index_counter = 0 for y in asks: asks_running_sum += float(y[1]) if asks_running_sum > 1000 and asks_index_counter == 0: sell_price_index = 0 undercut = True break elif asks_running_sum > 1000 and asks_index_counter > 0: sell_price_index = asks_index_counter - 1 undercut = False break else: sell_price_index = asks_index_counter undercut = False asks_index_counter += 1 if undercut == True: self.price_to_sell = self.low_ask_price - 1E-8 print('Undercutting') else: price_to_sell_txt = str(asks[sell_price_index][0]) self.price_to_sell = float(price_to_sell_txt) print('Sell price = ' + str(self.price_to_sell)) print('Buy price = ' + str(self.price_to_buy)) self.mod_spread = self.price_to_sell - self.price_to_buy print('Modified spread = ' + str(self.mod_spread)) if self.mod_spread <= 1.01E-8: self.place_orders_flag = False print( 'Set place orders flag to False because spread too small') elif self.price_to_sell <= self.high_bid_price: self.place_orders_flag = False print( 'Set place orders flag to false due to avoid cross-selling' ) elif self.price_to_buy >= self.low_ask_price: self.place_orders_flag = False print( 'Set place orders flag to false due to avoid cross-buying') else: self.place_orders_flag = True print('Set place orders flag to True, all conditions met') print('Place orders flag = ' + str(self.place_orders_flag))
class BotChart(object): def __init__(self, exchange, pair, period, backtest=True ): # TODO: pass in start and end timestamps for backtesting self.output = BotLog() self.exchange = exchange self.pair = pair self.period = period self.startTime = time.time( ) - SECONDS_IN_DAY * 2 # TODO: use passed in start and end timestamps self.endTime = time.time( ) # Backtest up to now TODO: move this to __init__ param so it can be changed self.data = [] if self.exchange == "kraken" and backtest: logger.info("Fetching historical OHLC data for back testing...") kraken_data = OHLC(pair='XXBTZUSD', since=self.startTime, interval=self.period) historical_kraken_data = kraken_data['result'][self.pair] for datum in historical_kraken_data: if datum[1] and datum[4] and datum[2] and datum[3] and datum[5]: # list entries: (0: <timestamp>, 1: <open>, 2: <high>, 3: <low>, 4: <close>, 5: <vwap>, 6: <volume>, 7: <count>) self.data.append( BotCandlestick(self.period, datum[1], datum[4], datum[2], datum[3], datum[5])) def get_points(self): return self.data def get_current_price_and_vol(self): """" Get last price from ticker """ current_values = Ticker() last_pair_price = current_values['result'][self.pair]['c'][0] last_pair_volume = current_values['result'][self.pair]['c'][1] # inside_bid = current_values['result'][self.pair]['b'][0] # inside_ask = current_values['result'][self.pair]['a'][0] return last_pair_price, last_pair_volume def get_ticker(self): """ Get ticker info :return dict of ticker results or empty dict if error. """ ticker = Ticker(pair=self.pair) if not ticker['error']: return ticker['result'] else: self.output.log(ticker) return {} def midpoint_price(self): """ The price between the best price of the sellers of the stock or commodity offer price or ask price and the best price of the buyers of the stock or commodity bid price. It can simply be defined as the average of the current bid and ask prices being quoted. AKA the "fair price". """ ticker = Ticker() best_bid_price = ticker.get('result')[self.pair]['b'][0] best_ask_price = ticker.get('result')[self.pair]['a'][0] return (float(best_bid_price) + float(best_ask_price)) / 2 def spread_percentage(self): """ Bid-Ask spread as a percentage. """ ticker = Ticker() b = ticker['result'][self.pair]['b'][0] a = ticker['result'][self.pair]['a'][0] return 100 * ((float(a) - float(b)) / float(a))
class BotAccount(object): def __init__(self, functions): self.output = BotLog() self.output.log("Getting balance data...") self.conn = functions.poloniex_conn self.data = self.__updateBalance() def getBalance(self): return self.data def createBalancePage(self): with open("balance.html", "w") as text_file: print("""<!DOCTYPE html> <html> <head> <style> table { font-family: arial, sans-serif; border-collapse: collapse; width: 100%; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } </style> </head> <body> <h1>BALANCE</h1><table id="example" class="display" cellspacing="0" width="100%"> <thead> <tr> <th>Pair</th> <th>Amount</th> </tr> </thead> <tfoot> <tr> <th>Pair</th> <th>Amount</th> </tr> </tfoot> <tbody> <tr>""", file=text_file) for k, v in self.data.items(): print("<tr><td>{0}</td><td>{1}</td></tr>".format(k, v), file=text_file) print("""</tbody> </table> <br/> <div align="right" > <button onclick="javascript:history.back()">Go back to index</button> </div> </body> </html>""", file=text_file) def __updateBalance(self): # return self.functions.getBalance() return {'BTC_XMR': 50, 'BTC_LTC': 20}
# Create the EventHandler and pass in your bot's token. updater = Updater(TELEGRAM_TOKEN) # Get the dispatcher to register handlers dp = updater.dispatcher # on different commands - answer in Telegram dp.add_handler(CommandHandler("start", self.start)) dp.add_handler(CallbackQueryHandler(self.button)) dp.add_handler(CommandHandler("help", self.help)) # on noncommand i.e message - echo the message on Telegram dp.add_handler(MessageHandler(Filters.text, self.onMessage)) # log all errors dp.add_error_handler(self.error_callback) # Start the Bot updater.start_polling() # Run the bot until you press Ctrl-C or the process receives SIGINT, # SIGTERM or SIGABRT. This should be used most of the time, since # start_polling() is non-blocking and will stop the bot gracefully. updater.idle() if __name__ == '__main__': log.log('Starting Telegram Bot') diag_telegram = DIAG_TLGM() diag_telegram.main()
class BotCandlestick(object): def __init__(self,date=None,open=None,high=None,low=None,close=None,volume=None): self.close = close self.currentPrice = close self.date = date self.high = high self.low = low self.open = open self.output = BotLog() self.priceAverage = False self.startTime = time.time() self.volume = volume if self.close: self.currentPrice = self.close def __setitem__(self, key, value): setattr(self, key, value) def __getitem__(self, key): return getattr(self, key) def toDict(self): return { 'close': self.close, 'currentPrice': self.currentPrice, 'date': self.date, 'high': self.high, 'low': self.low, 'open' : self.open, 'priceAverage': self.priceAverage, 'startTime': self.startTime, 'volume': self.volume } def tick(self, price): self.currentPrice = float(price) if self.date is None: self.date = time.time() if (self.open is None): self.open = self.currentPrice if (self.high is None) or (self.currentPrice > self.high): self.high = self.currentPrice if (self.low is None) or (self.currentPrice < self.low): self.low = self.currentPrice timedelta = utils.parseTimedelta(shared.strategy['timeframe']) if time.time() >= ( self.startTime + timedelta): self.close = self.currentPrice self.priceAverage = ( self.high + self.low + self.close ) / float(3) self.output.log("Start time: "+str(self.startTime)+", Open: "+str(self.open)+" Close: "+str(self.close)+" High: "+str(self.high)+" Low: "+str(self.low)+" currentPrice: "+str(self.currentPrice)) def isClosed(self): if (self.close is not None): return True else: return False
class BotStrategy(object): def __init__(self): self.output = BotLog() self.prices = [] self.opens = [] self.closes = [] #for Momentum self.trades = [] self.MACD_History = [] # MACD History self.MACD_Signal_History = [] # MACD Signal History self.currentPrice = None self.numSimulTrades = 1 self.takeProfit = 0.0001 self.stopLoss = 1 self.indicators = BotIndicators() self.trendPeriod = 3 # ETH : 3 # DASH : 3 self.minVolume = 1.2 # ETH : 1.2 # DASH : 1 def tick(self, candlestick): self.currentPrice = float(candlestick['weightedAverage']) self.currentVolume = float(candlestick['volume']) self.open = float(candlestick['open']) self.close = float(candlestick['close']) self.high = float(candlestick['high']) self.low = float(candlestick['low']) self.date = float(candlestick['date']) self.prices.append(self.currentPrice) self.closes.append(self.close) # for Momentum self.output.log("Price: " + str(candlestick['weightedAverage']) + "\tMoving Average: " + str(self.indicators.movingAverage(self.prices, 15)) + "\tMomentum: " + str(self.indicators.momentum(self.closes)) + "\tRSI: " + str(self.indicators.RSI(self.prices))) self.evaluatePositions() self.updateOpenTrades() self.showPositions() def evaluatePositions(self): MacdCurrent = None MacdPrevious = None SignalCurrent = None SignalPrevious = None openTrades = [] for trade in self.trades: if (trade.status == "OPEN"): openTrades.append(trade) if (len(openTrades) < self.numSimulTrades): #if (self.currentPrice < self.indicators.movingAverage(self.prices,15)): #if (float(ticker['BTC_ZEC']['percentChange']) < 0): #print("Momentum: " + str(self.indicators.momentum(self.closes))) #print("Pivot: " + str(self.indicators.Pivot('BTC_ZEC', 300,self.date))) # dont need to calculate this every tick #print("RSI : " + str(self.indicators.RSI(self.prices))) #slow, fast, signal = self.indicators.MACD(self.closes) #print(slow) #print(fast) #print(signal) if ( len(self.closes) > 26 + 2 ): # Need to have enought prices in order to calculate the slowEMA SlowEMA = (self.indicators.EMA(self.closes, 26)) FastEMA = (self.indicators.EMA(self.closes, 12)) self.MACD_History.append( self.indicators.iMACD(SlowEMA, FastEMA)) MacdCurrent = self.MACD_History[ -1] # this is the most recent MACD in the list if (len(self.MACD_History) > 2): MacdPrevious = ( self.MACD_History[-2] ) # This is the second most recent MACD in the List if (len(self.MACD_History) > 9 + 2): SignalCurrent = self.indicators.EMA(self.MACD_History, 9) self.MACD_Signal_History.append(SignalCurrent) if (len(self.MACD_Signal_History) > 2): SignalPrevious = self.MACD_Signal_History[-2] #print("MACD: ") #print(MacdCurrent) #print(MacdPrevious) #print(SignalCurrent) #print(SignalPrevious) if (len(self.closes) > 100): if (MacdCurrent and MacdPrevious and SignalCurrent and SignalPrevious): if (MacdCurrent < 0 and MacdCurrent > SignalCurrent and MacdPrevious < SignalPrevious and self.indicators.RSI(self.prices, 14) < 50): self.trades.append( BotTrade(self.currentPrice, stopLoss=self.stopLoss)) #if (self.indicators.trend(self.prices,self.trendPeriod) == 1 and self.currentVolume > self.minVolume): #self.trades.append(BotTrade(self.currentPrice,stopLoss=self.stopLoss)) #if (self.indicators.RSI(self.prices,14) < 30 and self.currentVolume > self.minVolume): # self.trades.append(BotTrade(self.currentPrice,stopLoss=self.stopLoss)) #print bcolors.WARNING + "Warning: No active frommets remain. Continue?" + bcolors.ENDC for trade in openTrades: currentProfit = float(self.currentPrice) - float(trade.entryPrice) if currentProfit > 0: print("entry: " + str(trade.entryPrice)) print(bcolors.OKGREEN + str(currentProfit) + bcolors.ENDC) else: print("entry: " + str(trade.entryPrice)) print(bcolors.WARNING + str(currentProfit) + bcolors.ENDC) #if (MacdCurrent and MacdPrevious and SignalCurrent and SignalPrevious): # if (MacdCurrent > 0 and MacdCurrent < SignalCurrent and MacdPrevious > SignalPrevious): if (self.currentPrice >= (float(trade.entryPrice) + self.takeProfit) or self.date > 1499309550 - 300): trade.close(self.currentPrice) #if (self.currentPrice > self.indicators.movingAverage(self.prices,15)): #if (self.indicators.trend(self.prices,self.trendPeriod) == 0 and self.currentVolume > self.minVolume): #if (self.indicators.RSI(self.prices,14) > 70 and self.currentVolume > self.minVolume): # trade.close(self.currentPrice) def updateOpenTrades(self): for trade in self.trades: if (trade.status == "OPEN"): trade.tick(self.currentPrice) def showPositions(self): for trade in self.trades: trade.showTrade()
class BotTrade(object): def __init__(self,direction,amount,rate,total,date,stopLoss=0, takeProfit=0, backtest=True, live=False): global orderNb self.amount = amount self.backTest = backtest self.date = date self.direction = direction self.exitDate = 0.0 self.exitRate = 0.0 self.fee = float(shared.exchange['fee']) self.filledOn = "" self.live = live self.orderNumber = orderNb self.output = BotLog() self.rate = rate self.status = "OPEN" self.stopLoss = stopLoss self.takeProfit = takeProfit self.total = total # API self.api = BotApi() orderSuccess = True if self.direction == "BUY": if not self.backTest and self.live: try: order = self.api.exchange.createLimitBuyOrder(shared.exchange['pair'], amount, rate) self.orderNumber = order['id'] except Exception as e: self.output.fail(str(e)) orderSuccess = False self.output.fail("Buy order failed") elif self.total < 0.00001: orderSuccess = False self.output.fail("Not enough funds to place Buy Order") if orderSuccess: shared.exchange['nbMarket'] -= self.total self.amount -= self.amount*self.fee self.output.info(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+": Buy "+str(self.amount)+' '+shared.exchange['asset']+' ('+str(self.fee*100)+'% fees) at '+str(self.rate)+' for '+str(self.total)+' '+shared.exchange['market']+' - stopLoss: '+str(self.stopLoss)+' - takeProfit: '+str(self.takeProfit)) elif self.direction == "SELL": if not self.backTest and self.live: try: order = self.api.exchange.createLimitSellOrder(shared.exchange['pair'], amount, rate) self.orderNumber = order['id'] except Exception as e: print(e) orderSuccess = False self.output.warning("Sell order failed") elif self.total < 0.00001: orderSuccess = False self.output.fail("Not enough funds to place Sell Order") if orderSuccess: shared.exchange['nbAsset'] -= self.amount self.total -= self.total*self.fee self.output.info(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+": Sell "+str(self.amount)+' '+shared.exchange['asset']+' at '+str(self.rate)+' for '+str(self.total)+' ('+str(self.fee*100)+'% fees) '+shared.exchange['market']+' - stopLoss: '+str(self.stopLoss)+' - takeProfit: '+str(self.takeProfit)) orderNb+=1 if not orderSuccess: self.status = 'FAILED' def __setitem__(self, key, value): setattr(self, key, value) def __getitem__(self, key): return getattr(self, key) def toDict(self): return { 'date': self.date, 'direction': self.direction, 'amount': self.amount, 'rate': self.rate, 'total': self.total, 'stopLoss': self.stopLoss, 'takeProfit': self.takeProfit, 'exitRate': self.exitRate, 'filledOn': self.filledOn, 'exitDate': self.exitDate, 'orderNumber': self.orderNumber } def tick(self, candlestick, date): if not self.backTest and self.live: date = float(time.time()) # TODO: implement not backtest pass if not self.filledOn: if (self.direction == 'BUY' and candlestick.high > self.rate) or (self.direction == 'SELL' and candlestick.low < self.rate): self.filledOn = date if self.direction == 'BUY': shared.exchange['nbAsset'] += self.amount elif self.direction == 'SELL': shared.exchange['nbMarket'] += self.total if not self.stopLoss and not self.takeProfit: self.status = 'CLOSED' else: if self.direction =='BUY': shared.exchange['coinsInOrder'] += self.amount elif self.direction =='SELL': shared.exchange['marketInOrder'] += self.total self.output.info(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+" filled") if self.stopLoss and self.filledOn: # TODO: implement live if self.direction == 'BUY' and candlestick.low < self.stopLoss: self.total -= self.total*self.fee shared.exchange['nbAsset'] -= self.amount shared.exchange['coinsInOrder'] -= self.amount self.output.warning(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+": Stop Loss - Sell "+str(self.amount)+' '+shared.exchange['asset']+' at '+str(self.stopLoss)+' for '+str(self.total)+' '+shared.exchange['market']+' ('+str(self.fee*100)+'% fees)') self.close(self.stopLoss, date) return elif self.direction == 'SELL' and candlestick.high > self.stopLoss: self.amount -= self.amount*self.fee shared.exchange['nbMarket'] -= self.total shared.exchange['marketInOrder'] -= self.total self.output.warning(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+": Stop Loss - Buy "+str(self.amount)+' '+shared.exchange['asset']+' ('+str(self.fee*100)+'% fees) at '+str(self.stopLoss)+' for '+str(self.total)+' '+shared.exchange['market']) self.close(self.stopLoss, date) return if self.takeProfit and self.filledOn: if self.direction == 'BUY' and candlestick.high > self.takeProfit: self.total -= self.total*self.fee shared.exchange['nbAsset'] -= self.amount shared.exchange['coinsInOrder'] -= self.amount self.output.success(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+": Take Profit - Sell "+str(self.amount)+' '+shared.exchange['asset']+' at '+str(self.stopLoss)+' for '+str(self.total)+' '+shared.exchange['market']+' ('+str(self.fee*100)+'% fees)') self.close(self.takeProfit, date) return elif self.direction == 'SELL' and candlestick.low < self.takeProfit: self.amount -= self.amount*self.fee shared.exchange['nbMarket'] -= self.total shared.exchange['marketInOrder'] -= self.total self.output.success(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+": Take Profit - Buy "+str(self.amount)+' '+shared.exchange['asset']+' ('+str(self.fee*100)+'% fees) at '+str(self.stopLoss)+' for '+str(self.total)+' '+shared.exchange['market']) self.close(self.takeProfit, date) return def close(self, currentPrice, date=0.0): if not self.backTest and self.live: date = float(time.time()) # TODO: implement not backtest pass self.status = "CLOSED" self.exitRate = currentPrice self.exitDate = date if self.direction == 'BUY': shared.exchange['nbMarket'] += self.total elif self.direction == 'SELL': shared.exchange['nbAsset'] += self.amount self.output.info(str(time.ctime(date)) + " - Order "+str(self.orderNumber)+" Closed") self.showTrade() def showTrade(self): tradeStatus = "Order #"+str(self.orderNumber)+" - Entry Price: "+str(self.rate)+" Status: "+str(self.status)+" Exit Price: "+str(self.exitRate) if (self.status == "CLOSED"): if (self.direction == 'BUY' and self.exitRate > self.rate) or (self.direction == 'SELL' and self.exitRate < self.rate): tradeStatus = tradeStatus + " Profit: \033[92m" else: tradeStatus = tradeStatus + " Loss: \033[91m" if self.direction == 'BUY': tradeStatus = tradeStatus+str((self.exitRate - self.rate)/self.total)+str(shared.exchange['market'])+"\033[0m" else: tradeStatus = tradeStatus+str((self.rate - self.exitRate)/self.exitRate*self.amount)+str(shared.exchange['asset'])+"\033[0m" self.output.log(tradeStatus) def updateStop(self, newStop): oldStop = self.stopLoss self.stopLoss = float(newStop); self.output.log("Trade stop moved from "+str(oldStop)+" to "+str(newStop))
class BotStrategy(object): def __init__(self, prices, pair, lengthMA, openPosLimit, stopLossEdge, entryEdge, timePosEdge): self.output = BotLog() self.prices = prices self.closes = [] # Needed for Momentum Indicator self.trades = [] self.currentPrice = 0 self.numSimulTrades = openPosLimit self.pair= pair self.side= "" self.lengthMA= lengthMA self.movAverage= 0 self.expMovAverage= 0 self.strategyTradingMetric= 0 self.allExecutions = executionsData() self.allTrades = tradesData() self.metrics= botMetrics() self.openedPositions =[] self.lastTradePnl=0 self.totalPnl=0 self.stopLossEdge= stopLossEdge self.entryEdge= entryEdge self.timePosEdge= timePosEdge def movingAverage(self, data, period): ma= 0 if len(data)> 1: ma= sum(data[-period:])/len(data[-period:]) return(ma) def tick(self, price, startTrade): self.currentPrice= price self.prices.append(self.currentPrice) self.movAverage= self.metrics.movingAverage(data=self.prices, period=self.lengthMA) self.expMovAverage = self.metrics.EMA(prices=self.prices, period=self.lengthMA) self.strategyTradingMetric= self.expMovAverage self.output.log("Price: " + str(round(price, 3)) + " MA: " + str(round(self.movAverage ,3)) + \ " EMA: "+str(round(self.expMovAverage ,3))) if startTrade: self.evaluatePositions() if self.stopLossEdge>0: self.updateOpenTrades() self.showPositions() self.updateOpenPositions() def evaluatePositions(self): currentTime= datetime.datetime.now() openTrades = [] for trade in self.trades: if (trade.status == "OPEN"): openTrades.append(trade) if (len(openTrades) < self.numSimulTrades): if ((self.strategyTradingMetric-self.currentPrice)> self.entryEdge): btrade= BotTrade(self.currentPrice, stopLossEdge=self.stopLossEdge) self.trades.append(btrade) self.updateExecutions(trade=btrade, executionTime=btrade.entryTime, executionPrice=btrade.entryPrice) for trade in openTrades: if (self.currentPrice > self.strategyTradingMetric): if (currentTime-trade.entryTime).seconds>self.timePosEdge: trade.close(self.currentPrice) self.updateExecutions(trade=trade, executionTime=trade.exitTime, executionPrice=trade.exitPrice) self.updateTrades(trade=trade) self.lastTradePnl= trade.pnl self.totalPnl= self.totalPnl+self.lastTradePnl def closeAll(self): for trade in self.trades: if (trade.status == "OPEN"): trade.close(self.currentPrice) self.updateExecutions(trade=trade, executionTime=trade.exitTime, executionPrice=trade.exitPrice) self.updateTrades(trade=trade) self.lastTradePnl = trade.pnl self.totalPnl = self.totalPnl + self.lastTradePnl self.trades= [] self.openedPositions =[] def updateExecutions(self, trade, executionTime, executionPrice): self.allExecutions.addExecutions(entryTime=executionTime, pair=self.pair, \ entryPrice=executionPrice, side=trade.side, pnl=trade.pnl) def updateTrades(self, trade): self.allTrades.addTrades(entryTime=trade.entryTime, exitTime=trade.exitTime, pair=self.pair,\ entryPrice=trade.entryPrice, exitPrice=trade.exitPrice, side=trade.side, pnl=trade.pnl) def updateOpenTrades(self): for trade in self.trades: if (trade.status == "OPEN"): if (self.currentPrice < trade.stopLoss): print("Exit StopLoss") self.output.log(crayons.magenta("Exit By Stop Loss")) trade.close(self.currentPrice) self.updateExecutions(trade=trade, executionTime=trade.exitTime, executionPrice=trade.exitPrice) self.updateTrades(trade=trade) self.lastTradePnl = trade.pnl self.totalPnl = self.totalPnl + self.lastTradePnl def updateOpenPositions(self): openedPositions = [] for trade in self.trades: if (trade.status=="OPEN"): openedPositions.append([trade.entryTime, self.pair, trade.side, \ round(trade.entryPrice,2), round(trade.pnl,2)]) self.openedPositions= openedPositions def showPositions(self): openedPositions= [] for trade in self.trades: trade.showStatus() return openedPositions def showOpenedPositions(self): temp= pd.DataFrame(self.openedPositions) if len(temp)>0: temp.columns= ["Time", "Pair", "Side", "EntryPrice", "Pnl"] return temp def showExecutions(self): temp= pd.DataFrame(self.allExecutions.execData) if len(temp)>0: temp.columns= ["Time", "Pair", "Price", "Side", "Pnl"] return temp def showTrades(self): temp = pd.DataFrame(self.allTrades.tradesData) if len(temp) > 0: temp.columns = ["EntryTime", "ExitTime", "Pair", "EntryPrice", "ExitPrice", "Side", "Pnl"] return temp def clearExecutions(self): self.allExecutions = executionsData() self.allTrades = tradesData()
class BotStrategy(object): def __init__(self): self.output = BotLog() self.prices = [] self.closes = [] # Needed for Momentum Indicator self.trades = [] self.currentPrice = "" self.currentClose = "" self.numSimulTrades = 1 self.indicators = BotIndicators() self.spreadsheet = [] def tick(self, candlestick): # print candlestick.priceAverage self.currentPrice = float(candlestick.priceAverage) self.prices.append(self.currentPrice) #self.currentClose = float(candlestick['close']) #self.closes.append(self.currentClose) self.output.log("Price: " + str(candlestick.priceAverage) + "\tMoving Average: " + str(self.indicators.movingAverage(self.prices, 15))) self.evaluatePositions() self.updateOpenTrades() self.showPositions() mess = str(candlestick['weightedAverage']) self.GenSpreadsheetInfo(self.prices) def evaluatePositions(self): openTrades = [] for trade in self.trades: if (trade.status == "OPEN"): openTrades.append(trade) if (len(openTrades) < self.numSimulTrades): if (self.currentPrice < self.indicators.movingAverage( self.prices, 20)): self.trades.append(BotTrade(self.currentPrice, stopLoss=.0001)) for trade in openTrades: if (self.currentPrice > self.indicators.movingAverage( self.prices, 20)): trade.close(self.currentPrice) def updateOpenTrades(self): for trade in self.trades: if (trade.status == "OPEN"): trade.tick(self.currentPrice) def showPositions(self): for trade in self.trades: trade.showTrade() def GenSpreadsheetInfo(self, prices): newList = [] if len(self.spreadsheet) == 0: newList.append("Price") newList.append("20_Per_MA") newList.append("50_per_MA") newList.append("TOP_STD") newList.append("BOT_STD") self.spreadsheet.append(newList) newList = [] newList.append(self.currentPrice) newList.append(self.indicators.movingAverage(self.prices, 20)) newList.append(self.indicators.movingAverage(self.prices, 50)) newList.append(self.currentPrice + (2 * self.indicators.standardDeviation(self.prices, 20))) newList.append(self.currentPrice - (2 * self.indicators.standardDeviation(self.prices, 20))) self.spreadsheet.append(newList) def GetSpreadsheetInfo(): return self.spreadsheet
class BotStrategy(object): def __init__(self): self.output = BotLog() self.prices = 0 self.trades = [] self.currentClose = "" self.numSimulTrades = 1 self.btc_historical_percent = 0 self.btc_historical_positive = 0 self.btc_historical_negative = 0 self.btc_historical_score = 0 self.btc_historical_total = 0 self.btc_sinceID = 0 self.btc_trading_percent = 0 self.eth_historical_percent = 0 self.eth_historical_positive = 0 self.eth_historical_negative = 0 self.eth_historical_score = 0 self.eth_historical_total = 0 self.eth_sinceID = 0 self.eth_trading_percent = 0 self.type_of_trade = '' self.api = bittrex('', '') self.btc_sentiments = [] self.eth_sentiments = [] def tick(self): currentPrice = self.api.getticker('BTC-ETH') self.prices = currentPrice['Ask'] #self.currentClose = float(candlestick['close']) #self.closes.append(self.currentClose) self.output.log("Price: " + '{0:.8f}'.format(self.prices)) self.evaluatePositions() self.updateOpenTrades() self.showPositions() def evaluatePositions(self): openTrades = [] for trade in self.trades: if (trade.status == "OPEN"): openTrades.append(trade) if (len(openTrades) < self.numSimulTrades): if (self.btc_historical_total <= 100000): bitcoin_query = 'BTC OR Bitcoin OR $BTC' btc_historical_tweets, self.btc_sinceid = tweets.get_tweets( 50, self.btc_sinceID, bitcoin_query) btc_total_score, btc_positive, btc_negative, btc_total = tweets.classify( btc_historical_tweets) self.btc_historical_positive = self.btc_historical_positive + btc_positive self.btc_historical_negative = self.btc_historical_negative + btc_negative self.btc_historical_score = self.btc_historical_score + btc_total_score self.btc_historical_total = self.btc_historical_total + btc_total self.btc_historical_percent = (self.btc_historical_positive / self.btc_historical_total) * 100 ethereum_query = 'Ethereum OR ETH OR $ETH' eth_historical_tweets, self.eth_sinceID = tweets.get_tweets( 50, self.eth_sinceID, ethereum_query) eth_total_score, eth_positive, eth_negative, eth_total = tweets.classify( eth_historical_tweets) self.eth_historical_positive = self.eth_historical_positive + eth_positive self.eth_historical_negative = self.eth_historical_negative + eth_negative self.eth_historical_score = self.eth_historical_score + eth_total_score self.eth_historical_total = self.eth_historical_total + eth_total self.eth_historical_percent = (self.eth_historical_positive / self.eth_historical_total) * 100 if self.btc_historical_total >= 100000: print '\033[1m' + "Historical Tweets Analyzed" print "historical btc percent: " + str( self.btc_historical_percent) print "historical eth percent: " + str( self.eth_historical_percent) print '\033[0m' elif (self.btc_historical_total > 100000): bitcoin_query = 'BTC OR Bitcoin OR $BTC' btc_tweets, sinceid_recent = tweets.get_tweets( 50, 0, bitcoin_query) btc_total_score2, btc_positive2, btc_negative2, btc_total2 = tweets.classify( btc_tweets) btc_percent = (btc_positive2 / btc_total2) * 100 ethereum_query = 'Ethereum OR ETH OR $ETH' eth_tweets, sinceid_recent = tweets.get_tweets( 50, 0, ethereum_query) eth_total_score2, eth_positive2, eth_negative2, eth_total2 = tweets.classify( eth_tweets) eth_percent = (eth_positive2 / eth_total2) * 100 if (eth_percent > 1.042 * self.eth_historical_percent or btc_percent < 0.943 * self.btc_historical_percent): if btc_percent < 0.943 * self.btc_historical_percent: self.btc_sentiments = [] self.btc_trading_percent = btc_percent self.type_of_trade = 'BTC' self.trades.append(BotTrade(self.prices, stopLoss=0.01)) elif (eth_percent > 1.042 * self.eth_historical_percent): self.eth_sentiments = [] self.eth_trading_percent = eth_percent self.type_of_trade = 'ETH' self.trades.append(BotTrade(self.prices, stopLoss=0.01)) else: self.type_of_trade = '' time.sleep(60 * 5) for trade in openTrades: if (self.type_of_trade == 'BTC'): bitcoin_query = 'BTC OR Bitcoin OR $BTC' btc_tweets, sinceid_recent = tweets.get_tweets( 10, 0, bitcoin_query) btc_total_score2, btc_positive2, btc_negative2, btc_total2 = tweets.classify( btc_tweets) btc_percent = (btc_positive2 / btc_total2) * 100 self.btc_sentiments.append(btc_percent) if (len(self.btc_sentiments) > 5): mean_sentiment = np.mean(self.btc_sentiments) std_sentiment = np.std(self.btc_sentiments) if btc_percent >= mean_sentiment + ( (0.800 * std_sentiment) / math.sqrt(len(self.btc_sentiments))): price = self.api.getticker('BTC-ETH') self.currentClose = price['Bid'] trade.close(self.currentClose) else: time.sleep(60 * 3) elif (self.type_of_trade == 'ETH'): ethereum_query = 'Ethereum OR ETH OR $ETH' eth_tweets, sinceid_recent = tweets.get_tweets( 10, 0, ethereum_query) eth_total_score2, eth_positive2, eth_negative2, eth_total2 = tweets.classify( eth_tweets) eth_percent = (eth_positive2 / eth_total2) * 100 self.eth_sentiments.append(eth_percent) if (len(self.eth_sentiments) > 5): mean_sentiment = np.mean(self.eth_sentiments) std_sentiment = np.std(self.eth_sentiments) if eth_percent <= mean_sentiment - ( (0.674 * std_sentiment) / math.sqrt(len(self.eth_sentiments))): price = self.api.getticker('BTC-ETH') self.currentClose = price['Bid'] trade.close(self.currentClose) else: time.sleep(60 * 3) else: price = self.api.getticker('BTC-ETH') self.currentClose = price['Bid'] trade.close(self.currentClose) def updateOpenTrades(self): for trade in self.trades: if (trade.status == "OPEN"): trade.tick(self.prices) def showPositions(self): for trade in self.trades: trade.showTrade()
class BotTrade(object): def __init__(self, pair, current_price, trade_type=None, order_type='market', stop_loss_percent=0): self.output = BotLog() self.pair = pair self.status = "OPEN" self.entry_price = 0.0 self.exit_price = 0.0 self.entry_cost = 0.0 self.exit_cost = 0.0 self.profit = 0.0 self.fees = 0.0 self.fee_percentage = 0.0 self.exit_minus_entry_less_fees = 0.0 self.trade_pl = None self.trade_net_precent = 0.0 self.trade_type = trade_type # BUY/SELL self.order_type = order_type # Market/Limit/stop loss/settle position/etc. self.min_bid = 0.002 self.open_time = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') self.close_time = "---------- --:--:--" self.stop_loss_percent = stop_loss_percent self.open_order_id = "" self.close_order_id = "" # user reference id. 32-bit signed number. # 1-bit for sign, 3-bits for 3 decimal digit (0-999), 8-bits for for randomly generated id. self.user_ref_id = int(str(BOT_ID) + str(int(random.getrandbits(7)))) # self.usd_balance = float(Balance()) # Set volume to higher of 1% of wallet and min bid # self.bid_volume = max(self.usd_balance * 0.01 / current_price, 0.002) if current_price else 0.002 self.bid_volume = 0.002 # Instantiating a BotTrade object is equivalent to opening a trade. TODO: move open to a function if self.trade_type.upper() == 'BUY': self._handle_entry_order('buy', current_price) if self.trade_type.upper() == 'SELL': self._handle_entry_order('sell', current_price) statsd.increment('open.order', tags=['name:{}'.format(BOT_NAME), 'pair:{}'.format(self.pair), 'type:{}'.format(self.trade_type), 'order:{}'.format(self.order_type), 'volume:{}'.format(self.bid_volume), 'cur_price:{}'.format(current_price), 'bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.increment('total_trading_volume', self.entry_cost, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.event(title='Order Open', text='{}/{} - {} {} @ {} / Cost: {}'.format(self.open_order_id, self.pair, self.trade_type, self.bid_volume, self.entry_price, self.entry_cost), alert_type='success', tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) self.output.log("{c1}{trade_type} Trade opened - order_id: {order_id}{c2}".format(c1=Yellow, trade_type=self.trade_type.upper(), order_id=self.open_order_id, c2=White)) # TODO: Implement trailing stop loss - might be available on Kraken as a special order type # TODO: Implement a daily stop loss, 3% of wallet self.stop_loss = current_price * (1.0 - (stop_loss_percent / 100)) if stop_loss_percent else 0 def close(self, current_price): self.status = "CLOSED" self.close_time = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') if self.trade_type.upper() == "BUY": # Make oppostie trade type to close self._handle_exit_order('sell', current_price) elif self.trade_type.upper() == "SELL": # Make oppostie trade type to close self._handle_exit_order('buy', current_price) statsd.increment('close.order', tags=['name:{}'.format(BOT_NAME), 'pair:{}'.format(self.pair), 'type:{}'.format(self.trade_type), 'order:{}'.format(self.order_type), 'volume:{}'.format(self.bid_volume), 'cur_price:{}'.format(current_price), 'bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.event(title='Order Close', text='{}/{} - {} {} @ {} / Cost: {}'.format(self.close_order_id, self.pair, self.trade_type, self.bid_volume, self.exit_price, self.exit_cost), alert_type='success', tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) self.output.log("{c1}{trade_type} Trade closed - order_id: {order_id}{c2}".format(c1=Yellow, trade_type=self.trade_type.upper(), order_id=self.close_order_id, c2=White)) if self.profit >= 0.0: self.output.log("Profit/Loss before fees {}".format(self.profit)) statsd.increment('bottrade.profit', self.profit, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.increment('bottrade.win_rate', 1, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) else: self.output.log("Profit/Loss before fees {}".format(self.profit)) # Decrement by the absolute value if profit is negative statsd.decrement('bottrade.profit', abs(self.profit), tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) statsd.decrement('bottrade.win_rate', 1, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) self.output.log("Trade fees at closing: {}".format(self.fees)) statsd.increment('trading_fees', self.fees, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) def tick(self, current_price): if self.stop_loss: if current_price < self.stop_loss: # TODO: Does this work for short trade? self.output.log("Closed on stop loss set to {}".format(self.stop_loss_percent)) self.close(current_price) def show_trade(self): trade_status = "{c1}{open_time} / {close_time} {order_id} {c2}{order_type}{c3} {bid_vol} @ {entry_price} = ${cost}{c1} {close_order_id} {status} Exit Price: {exit_price}".format( bid_vol=self.bid_volume, open_time=self.open_time, close_time=self.close_time, entry_price=str(self.entry_price), cost=str(self.entry_cost), status=str(self.status), exit_price=str(self.exit_price), order_id=str(self.open_order_id), close_order_id=str(self.close_order_id), order_type=str(self.trade_type), c1=Purple, c2=Red, c3=Cyan) # TODO: Refactor if self.status == "CLOSED": trade_status = trade_status + " P/L: " self.exit_minus_entry_less_fees = (self.exit_price - self.entry_price) - self.fees if self.exit_minus_entry_less_fees > 0: if self.trade_type.upper() == 'BUY': trade_status = trade_status + Green elif self.trade_type.upper() == 'SELL': trade_status = trade_status + Red self.exit_minus_entry_less_fees = (self.exit_price - self.entry_price) - self.fees elif self.exit_minus_entry_less_fees < 0: if self.trade_type.upper() == 'BUY': trade_status = trade_status + Red elif self.trade_type.upper() == 'SELL': trade_status = trade_status + Green self.exit_minus_entry_less_fees = (self.entry_price - self.exit_price) - self.fees else: trade_status = trade_status + White # Percent change in market. if self.exit_price > 0: self.trade_net_precent = 100 * (float(self.exit_price) - (self.entry_price)) / self.exit_price self.trade_pl = round((self.entry_price * self.bid_volume) * (self.trade_net_precent / 100) - self.fees, 4) else: self.trade_net_precent = 0 self.trade_pl = 0 trade_status = trade_status + " $" + str(self.trade_pl) + " | $" + str(self.exit_minus_entry_less_fees) + " (" + str(round(self.trade_net_precent, 3)) + "%)" + White self.output.log(trade_status + White) @staticmethod def get_order_price(order_obj): order_id = order_obj.get('result').keys()[0] return float(order_obj.get('result', {}).get(order_id, {}).get('price')) def get_trade_fee_from_order_object(self, order_obj): """ Given a filled order object extracts the trade fee from the associated trade object. :param order_obj = Full order object from calling QueryOrders() Returns None if order has not yet been filled. Returns trade fee amount in dollars. """ fees = 0.0 try: result = order_obj.get('result', {}) order_id = next(iter(result)) trade_id_lst = order_obj.get('result', {}).get(order_id, {}).get('trades') for id in trade_id_lst: trade = QueryTrades(id) result = trade.get('result', {}) trade_obj = result.get(id, {}) trade_fee = float(trade_obj.get('fee')) fees += trade_fee return fees except Exception: return fees def _handle_entry_order(self, trade_type, current_price): response = AddOrder(self.pair, trade_type.lower(), self.order_type.lower(), self.bid_volume, round(current_price, 1), userref=self.user_ref_id, validate=VALIDATE) # Used in paper trading and backtesting if VALIDATE: self.entry_price = current_price self.entry_cost = self.entry_price * self.bid_volume self.fee_percentage = float(TradeVolume().get('result', {}).get('fees', {}).get(self.pair, {}).get('fee', 0.2600)) / 100 self.output.log("fee_percentage: {}".format(self.fee_percentage)) self.output.log("Trade entry cost {}".format(self.entry_cost)) self.fees += float(self.entry_cost) * self.fee_percentage if response is not None and not response['error']: # Extract order id self.open_order_id = response.get('result', {'txid': 'N/A'}).get('txid', 'N/A')[0] self.open_order_obj = QueryOrders(self.open_order_id, trades=True) if not self.open_order_obj['error']: # Extract order price self.entry_price = self.get_order_price(self.open_order_obj) if not VALIDATE else current_price * self.bid_volume self.entry_cost = self.entry_price * self.bid_volume self.output.log("Trade entry cost {}".format(self.entry_cost)) # Extract fees self.fees += self.get_trade_fee_from_order_object(self.open_order_obj) if not VALIDATE else 0.0 if not __debug__: msg = json.dumps(response.get('result', {})) slack.post("`{}`\n`Price: {} fee: {} cost: {}`".format(msg, self.entry_price, self.fees, self.entry_cost), username=BOT_NAME) def _handle_exit_order(self, trade_type, current_price): response = AddOrder(self.pair, trade_type.lower(), self.order_type.lower(), self.bid_volume, round(current_price, 1), userref=self.user_ref_id, validate=VALIDATE) # Used in paper trading and backtesting if VALIDATE: self.exit_price = current_price self.exit_cost = self.exit_price * self.bid_volume self.output.log("fee_percentage: {}".format(self.fee_percentage)) self.output.log("Trade entry cost {}".format(self.exit_cost)) self.profit = self.exit_cost - self.entry_cost self.fees += float(self.exit_cost) * float(self.fee_percentage) if response is not None and not response['error']: # Extract order id. self.close_order_id = response.get('result', {'txid': '-'}).get('txid', '-')[0] self.close_order_obj = QueryOrders(self.close_order_id, trades=True) if not self.close_order_obj['error']: # Extract order price self.exit_price = self.get_order_price(self.close_order_obj) if not VALIDATE else current_price * self.bid_volume self.exit_cost = self.exit_price * self.bid_volume self.profit = self.exit_cost - self.entry_cost self.output.log("Trade exit cost {}".format(self.entry_cost)) # Extract fees self.fees += self.get_trade_fee_from_order_object(self.close_order_obj) if not VALIDATE else 0 if not __debug__: msg = json.dumps(response.get('result', {})) slack.post("`{}`\n`Price: {} fee: {} cost: {}`".format(msg, self.exit_price, self.fees, self.exit_cost), username=BOT_NAME)
def main(argv): """ Main entry point """ # Logging output = BotLog() supported_exchanges = ['kraken'] exchange = 'kraken' pair = "XXBTZUSD" # Bitcoin/USD pair on Kraken period = 5 # Time frame interval in minutes, e.g. width of candlestick. poll_time = 1 # How often an API query is made when using real time data. script_help = '\n\t-c --currency <currency pair>\n\t-x --exchange <name of the exchange {exchanges}>\n\t-t --poll <poll period length in minutes>\n\nHistorical Mode\n\t-p --period <period of frame>\n\t-s --start <start time in unix timestamp>\n\t-e --end <end time in unix timestamp>\n'.format( exchanges=supported_exchanges) start_time = False end_time = False try: opts, args = getopt.getopt( argv, "h:x:p:c:t:s:e:y:", ["exchange=", "period=", "currency=", "poll=", "start=", "end="]) except getopt.GetoptError: output.log(sys.argv[0] + script_help) sys.exit(2) for opt, arg in opts: if opt == ("-h", "--help"): output.log(sys.argv[0] + script_help) sys.exit() elif opt in ("-s", "--start"): start_time = arg elif opt in ("-e", "--end"): end_time = arg elif opt in ("-x", "--exchange"): if arg in supported_exchanges: exchange = arg else: output.log( 'Supported exchanges are {}'.format(supported_exchanges)) sys.exit(2) elif opt in ("-p", "--period"): if exchange.lower() == 'kraken': # Kraken uses minutes for getting historical data. mins = [1, 5, 15, 30, 60, 240, 1440, 10080, 21600] if (int(arg) in mins): period = int(arg) else: output.log( 'Kraken requires intervals 1, 5, 15, 30, 60, 240, 1440, 10080, 21600 minute intervals' ) sys.exit(2) else: period = int(arg) elif opt in ("-c", "--currency"): pair = arg elif opt in ("-t", "--poll"): poll_time = arg ################ Strategy in use ################ strategy = MACDStrategy(pair, period) strategy_name = strategy.get_name() ################################################# # Log bot startup event to DataDog statsd.event(title='Bot started', text='{}:{} started on {} trading {} using {}'.format( BOT_ID, BOT_NAME, exchange, pair, strategy_name), alert_type='success', tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) trade_session_details = "{bg}Trading {pair} on {exchange} with {strat}" \ " @ {period} minute period{White}".format(pair=pair, exchange=exchange.upper(), strat=strategy_name, period=period, bg=On_Cyan, White=White) if start_time: # Backtesting chart = BotChart(exchange, pair, period) for candlestick in chart.get_points(): strategy.tick(candlestick) output.log(trade_session_details) else: # Live Trading output.log(trade_session_details) chart = BotChart(exchange, pair, period, backtest=False) candlesticks = [] developing_candlestick = BotCandlestick(period) progress_counter = 0 while True: # Log trade details every so often if progress_counter == 50: output.log(trade_session_details) progress_counter = 0 progress_counter += 1 try: developing_candlestick.tick( chart.get_current_price_and_vol()[0]) except urllib2.URLError, err: # If network or site is down output.log("{}... Continuing".format(err[0])) # TODO: These calls to statsd should be Rollbar. Set up Rollbar statsd.histogram( 'main_loop.urllib2.URLError', err, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) continue except ValueError, err: # For screwy JSON output.log('{}... Continuing'.format(err[0])) statsd.histogram( 'main_loop.ValueError', err, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) continue except urllib2.ssl.SSLError, err: # For read timeouts output.log("{}... Continuing".format(err[0])) statsd.histogram( 'main_loop.urllib2.ssl.SSLError', err, tags=['bot_name:{}.bot_id:{}'.format(BOT_NAME, BOT_ID)]) continue
class BotTrade(object): def __init__(self, order_num, currentPrice, type_trade, loss_break): self.output = BotLog() self.status = "OPEN" self.entryPrice = currentPrice self.exitPrice = "" self.output.log("Trade opened") self.type_trade = type_trade self.exit_time = False self.Order_num = order_num self.Loss_break = loss_break self.Balance = False self.GRC_bal = False self.BTC_bal = False self.pair = "BTC_GRC" self.out_amount = False def close(self, currentPrice): self.status = "CLOSED" self.exitPrice = currentPrice self.output.log("Trade closed") self.exit_time = datetime.datetime.now() polo.cancelOrder(self.Order_num) def tick(self, currentPrice): if currentPrice > self.Loss_break * 1.1: self.close(currentPrice) self.get_out(currentPrice) def get_out(self, currentPrice): self.Balance = polo.returnBalances() self.GRC_bal = float((self.Balance['GRC'])) self.BTC_bal = float((self.Balance['BTC'])) self.out_amount = self.BTC_bal / float(currentPrice) polo.buy(self.pair, currentPrice, self.out_amount) sys.exit() def showTrade(self): tradeStatus = "Order #: " + str( self.Order_num) + " Entry Price: " + str( self.entryPrice) + " Status: " + str( self.status) + " Exit Price: " + str( self.exitPrice) + " Trade Type " + str(self.type_trade) #+ " Exit Time: " + str(self.exit_time if (self.status == "CLOSED") and self.type_trade == "LONG": tradeStatus = tradeStatus + " Profit: " if (self.exitPrice > self.entryPrice): tradeStatus = tradeStatus + "\033[92m" else: tradeStatus = tradeStatus + "\033[91m" tradeStatus = tradeStatus + str(self.exitPrice - self.entryPrice) + "\033[0m" elif (self.status == "CLOSED") and self.type_trade == "SHORT": tradeStatus = tradeStatus + " Profit: " if (self.exitPrice < self.entryPrice): tradeStatus = tradeStatus + "\033[92m" else: tradeStatus = tradeStatus + "\033[91m" tradeStatus = tradeStatus + str(self.entryPrice - self.exitPrice) + "\033[0m" self.output.log(tradeStatus)
class BotStrategy(object): def __init__(self): #connect; read and write to db self.TradeDatabase = TradeDatabase() self.TradeDatabase.connect() #amount to trade (capital): self.amountInUSD = 300 #prices information self.prices = [] self.currentPrice = "" #graph and indicators self.output = BotLog() self.indicators = BotIndicators() #self.graphdataPoints = [] self.dataDate = "" self.SMA = "" self.CResistance = 0.0 self.EMA9 = [] self.MACD = [] #trade details self.tradePlaced = [] self.typeOfTrade = [] self.cumulatedProfits = 0.0 #wins and loses self.numofwins = 0 self.numofloses = 0 def tick(self): #only call API once try: self.APIlist = FinexAPI.ticker() except: try: time.sleep(10) self.APIlist = FinexAPI.ticker() except: try: time.sleep(10) self.APIlist = FinexAPI.ticker() except: pass #date self.dataDate = datetime.datetime.fromtimestamp( int(float( self.APIlist["timestamp"]))).strftime('%Y-%m-%d %H:%M:%S') #prices self.currentPrice = float(self.APIlist["last_price"]) #insert into SQL db self.TradeDatabase.insertStatement01(self.dataDate, self.currentPrice) #load datelist, prices from db self.datelist, self.prices = self.TradeDatabase.readtolist01() #indicators self.SMA = self.indicators.movingAverage(self.prices, 200) self.CResistance = self.indicators.trendline(self.prices) self.RSI = self.indicators.RSI(self.prices) #macd indicators & insert into DB if len(self.prices) > 26: #get macd indicators emaslow, emafast, self.MACD = self.indicators.MACD(self.prices) self.EMA9 = self.indicators.EMA(self.MACD, 9) #Insert all to DB (no need for macd and ema9 - they are self generated and contained lists) self.TradeDatabase.insertStatement02(self.dataDate, self.CResistance, self.SMA, self.RSI) #graph #archaic : self.graphdataPoints.append({'date':self.dataDate, 'price': self.currentPrice, 'trend': self.CResistance, 'SMA': self.SMA, 'RSI':self.RSI, 'short': np.nan, 'long':np.nan,'closedLong':np.nan,'closedShort':np.nan}) #graph with pdDataFrame obj self.graphdataPoints = self.TradeDatabase.frameit() #if/else indicators self.tradePlaced, self.typeOfTrade, self.cryptoAmount = self.TradeDatabase.readtolist02( ) self.tradePlaced = [i for i in self.tradePlaced if i * 0 == 0] #only get the numbers self.typeOfTrade = [i for i in self.typeOfTrade if i != None] #only get the strings self.cryptoAmount = [i for i in self.cryptoAmount if i * 0 == 0] #only get the numbers #print timestamp and price to cmd line for logging purposes self.output.log(self.dataDate + "\tPrice: " + str(self.currentPrice) + "\tMoving Average: " + str(self.SMA)) #print numofwins, numofloses and cumulated profits to cmd line self.cumulatedProfits, self.numofwins, self.numofloses = self.TradeDatabase.cumwinloss( ) self.output.log( "No. of Wins: {}, No. of Loses: {}, Cumulated Profits: {}".format( self.numofwins, self.numofloses, self.cumulatedProfits)) #decide when to buy and when to sell - MACD strat + 200 period SMA - maybe can implement stops (?) GOLDEN GRAIL!!! def evaluatePositions(self): try: if len(self.tradePlaced) == 0 or self.tradePlaced[-1] == 0: #if market is bullish - only take buy signals if self.currentPrice > self.SMA: #MACD indicator - when EMA9 crosses higher than the MACD curve - buy if (len(self.MACD) > 1) and ( self.EMA9[-2] < self.MACD[-2]) and (self.EMA9[-1] > self.MACD[-1]): self.buyposition() #elif market is bearish - only take sell signals elif self.currentPrice < self.SMA: #MACD indicator - when EMA9 crosses lower than the MACD curve - sell if (len(self.MACD) > 1) and ( self.EMA9[-2] > self.MACD[-2]) and (self.EMA9[-1] < self.MACD[-1]): self.sellposition() elif self.typeOfTrade[-1] == "long": #MACD indicator - when EMA9 crosses lower than the MACD curve - sell if ((self.EMA9[-2] > self.MACD[-2]) and (self.EMA9[-1] < self.MACD[-1]) and (self.cryptoAmount[-1] * self.currentPrice > 0.95 * self.amountInUSD)): self.closeLong() #if bullish trend ends and you are stuck, immediately sell to recoup loss elif self.currentPrice < self.SMA: self.closeLong() elif self.typeOfTrade[-1] == "short": #MACD indicator - when EMA9 crosses higher than the MACD curve - buy if ((self.EMA9[-2] < self.MACD[-2]) and (self.EMA9[-1] > self.MACD[-1]) and (0.996 * self.amountInUSD) > 0.95 * (self.currentPrice * self.cryptoAmount[-1])): self.closeShort() #if bearish trend ends and you are stuck, immediately buy to recoup loss elif self.currentPrice > self.SMA: self.closeShort() except TypeError: pass #buy and sell positions def buyposition(self): amountincryptos = 0.996 * float(self.amountInUSD) / self.currentPrice self.output.log("BUY {} Cryptos at {}USD".format( amountincryptos, self.amountInUSD)) self.TradeDatabase.insertStatement03(self.dataDate, amountincryptos, self.currentPrice, 1, "long") def sellposition(self): amountincryptos = float(self.amountInUSD) / self.currentPrice self.output.log("SELL {} Cryptos at {}USD".format( amountincryptos, self.amountInUSD)) self.TradeDatabase.insertStatement04(self.dataDate, amountincryptos, self.currentPrice, 1, "short") def closeLong(self): netProfit = self.cryptoAmount[-1] * self.currentPrice - self.amountInUSD self.TradeDatabase.insertStatement05(self.dataDate, netProfit) self.cumulatedProfits, self.numofwins, self.numofloses = self.TradeDatabase.cumwinloss( ) self.TradeDatabase.insertStatement06(self.dataDate, self.currentPrice, 0) if netProfit >= 0: self.output.log( "Closed LONG ORDER at {}".format(self.currentPrice) + self.output.color("\tNet Profit: {}".format(netProfit), 'green') + "\tCumulated Profits: {}".format(self.cumulatedProfits)) self.output.log( "No. of Wins: {}, No. of Loses: {}, Win Rate: {}".format( self.numofwins, self.numofloses, round(self.numofwins / (self.numofwins + self.numofloses), 2))) else: self.output.log( "Closed LONG ORDER at {}".format(self.currentPrice) + self.output.color("\tNet Profit: {}".format(netProfit), 'red') + "\tCumulated Profits: {}".format(self.cumulatedProfits)) self.output.log( "No. of Wins: {}, No. of Loses: {}, Win Rate: {}".format( self.numofwins, self.numofloses, round(self.numofwins / (self.numofwins + self.numofloses), 2))) def closeShort(self): netProfit = (0.996 * self.amountInUSD) - (self.currentPrice * self.cryptoAmount[-1]) self.TradeDatabase.insertStatement05(self.dataDate, netProfit) self.cumulatedProfits, self.numofwins, self.numofloses = self.TradeDatabase.cumwinloss( ) self.TradeDatabase.insertStatement07(self.dataDate, self.currentPrice, 0) if netProfit >= 0: self.output.log( "Closed SHORT ORDER at {}".format(self.currentPrice) + self.output.color("\tNet Profit: {}".format(netProfit), 'green') + "\tCumulated Profits: {}".format(self.cumulatedProfits)) self.output.log( "No. of Wins: {}, No. of Loses: {}, Win Rate: {}".format( self.numofwins, self.numofloses, round(self.numofwins / (self.numofwins + self.numofloses), 2))) else: self.output.log( "Closed SHORT ORDER at {}".format(self.currentPrice) + self.output.color("\tNet Profit: {}".format(netProfit), 'red') + "\tCumulated Profits: {}".format(self.cumulatedProfits)) self.output.log( "No. of Wins: {}, No. of Loses: {}, Win Rate: {}".format( self.numofwins, self.numofloses, round(self.numofwins / (self.numofwins + self.numofloses), 2)))