Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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))