Exemple #1
0
class BittrexExchange(object):
    def __init__(self, config={}):
        self.api = Bittrex()
        self.balance = None

    def buy(self, buyOrder):
        r = self.api.market_buylimit(buyOrder["market"], buyOrder["qty"],
                                     buyOrder["price"]).getData()
        if r["success"]:
            buyOrder["id"] = r["result"]["uuid"]
        else:
            buyOrder["status"] = "error"

        return buyOrder

    def sell(self, sellOrder):
        r = self.api.market_selllimit(sellOrder["market"], sellOrder["qty"],
                                      sellOrder["price"]).getData()
        if r["success"]:
            sellOrder["id"] = r["result"]["uuid"]
        else:
            sellOrder["status"] = "error"
            print(r)
        return sellOrder

    def cancel(self, orderId):
        r = self.api.market_cancel(orderId).getData()
        return r

    def getOrderStatusDirect(self, orderId):
        r = self.api.account_get_order(orderId).getData()
        return r

    def getOrderStatus(self, orderId):
        resp = self.getOrderStatusDirect(orderId)
        # print(resp)

        status = "pending"

        if resp["result"]["Quantity"] != resp["result"]["QuantityRemaining"]:
            status = "partial"

        if not resp["result"]["IsOpen"]:
            status = "completed"

        if resp["result"]["CancelInitiated"]:
            status = "cancelled"

        return {
            "status": status,
            "remaining": resp["result"]["QuantityRemaining"],
            "commissionPaid": resp["result"]["CommissionPaid"],
            "opened": resp["result"]["Opened"],
            "closed": resp["result"]["Closed"]
        }

    def processOrder(self, order):
        order.setExchange(self.getName())
        self.log.info("bittrex exchange processing order")
        if order.rate != order.MARKET:
            if order.order_type == order.SELL:
                r = self.api.market_selllimit(order.market, order.qty,
                                              order.rate).getData()
            elif order.order_type == order.BUY:
                r = self.api.market_buylimit(order.market, order.qty,
                                             order.rate).getData()

            if r["success"]:
                order.ref_id = r["result"]["uuid"]
                order.status = order.OPEN
            else:
                order.status = order.ERROR

            order.meta["api"] = {"create": r}
            res = order.save()
            self.log.info("save results {}".format(res))
            return Result(r["success"], r["message"], r["result"])
        else:
            return Result.fail("Market orders not allowed on bittrex")

    def syncOrder(self, order):
        if order.status < order.TERMINATED_STATE:
            status = order.status
            results = self.api.account_get_order(order.ref_id)
            data = results.getData()
            if data["success"]:
                res = data["result"]
                if res["CancelInitiated"]:
                    order.status = order.CANCELLED
                elif not res["IsOpen"] and res["Type"] == "LIMIT_SELL":
                    order.status = order.COMPLETED
                elif not res["IsOpen"] and res["Type"] == "LIMIT_BUY":
                    order.status = order.FILLED
                elif res["IsOpen"] and not res["Quantity"] > res[
                        "QuantityRemaining"] and order.status != order.PARTIAL_FILL:
                    order.status = order.PARTIAL_FILL

                if status != order.status or "state" not in order.meta["api"]:
                    self.log.info("found updates to order {}".format(
                        order.ref_id))
                    order.meta["api"]["state"] = data
                    order.save()
                    if order.status == order.COMPLETED:  # and order.order_type == Order.SELL:
                        self.log.info(
                            "looking for associated order: {}".format(
                                order.assoc_id))
                        assocorder = Order.findById(order.assoc_id)
                        if assocorder.isOk():
                            aorder = assocorder.data["results"][0]
                            aorder.status = Order.COMPLETED
                            self.log.info("found associated order {}".format(
                                aorder.ref_id))
                            #instead get this rate from the api results...
                            aorder.meta["sold_at"] = data["result"][
                                'PricePerUnit']
                            aorder.assoc_id = order.pkey  #data["result"]['PricePerUnit']
                            res = aorder.save()
                            self.log.info(
                                "saved associated order {}".format(res))

                    return True

    def getBalance(self, currency):
        if self.balance is None:
            self.getBalances()

        currency = currency.upper()
        if currency in self.balance:
            return self.balance[currency]["Available"]

    def getBalances(self):
        results = self.api.account_get_balances().getData()
        if results["success"]:
            self.balance = {}
            for c in results["result"]:
                self.balance[c["Currency"]] = c

        return self.balance
Exemple #2
0
class CoinWatch(object):

    def __init__(self, config={}):
        self.bittrex = Bittrex()
        self.mongo = MongoWrapper.getInstance().getClient()
        self.history = None
        self.pendingorders = None
        self.bal = None

    def setupWatch(self):
        res = self.mongo.crypto.drop_collection("watch")
        #res = self.mongo.crypto.create_collection("watch")
        #res = self.mongo.crypto.watch.create_index([("name",pymongo.ASCENDING)],unique=True)


    def updateWatch(self, watch ):
        if "_id" in watch:
            searchDoc = {"_id": ObjectId(watch["_id"])}
            del watch["_id"]
        else:
            searchDoc = {"name": watch.get("name"), "exchange": watch.get("exchange")}
        return self.mongo.crypto.watchlist.replace_one(searchDoc, watch , upsert=True)


    def update(self, watch):
        if "name" in watch:
            return self.mongo.crypto.watchlist.replace_one({'name':watch['name']},watch,upsert=True)

    def removeWatch(self, market,exchange):
        if market is not None:
            return self.mongo.crypto.watchlist.delete_one({'name':market, 'exchange': exchange})


    def loadWatchList(self,search = {}):
        res = self.mongo.crypto.watchlist.find(search)
        allrows = list(res)
        watchlist = []
        headers = []
        for row in allrows:
            for key in row:
                if key not in headers:
                    headers.append(key)

        for row in allrows:
            r = {}
            for head in headers:
                if head in row:
                    r[head] = row[head]
                else:
                    r[head] = None
            watchlist.append(r)

        return watchlist

    def refresh(self):
        self.history  = self.bittrex.account_get_orderhistory().data["result"]
        self.bal = self.bittrex.account_get_balances().data["result"]
        self.pendingorders = self.bittrex.market_get_open_orders().data["result"]

    def tableize(self, rows, headers = None, margin = 2):

        if len(rows) == 0:
            return

        headers = []
        mincol = {}
        for row in rows:
            for c in row:
                col = str(c)
                if col not in headers:
                    headers.append(col)
                    mincol[col] = len(col)

        for row in rows:
            for head in headers:
                if head in row:
                    hl = len(str(row[head]))
                    if hl > mincol[head]:
                        mincol[head] = hl

        for head in headers:
            print("{}".format(head.ljust(mincol[head]+margin)), end="")
        print("")

        for row in rows:
            for head in headers:
                if head in row and row[head] is not None:
                    col = str(row[head])
                else:
                    col = ""

                print("{}".format(col.ljust(mincol[head]+margin)), end="")
            print("")

    def xtableize(self, rows):

        hid = 0
        hl = 0
        for idx, row in enumerate(rows):
            if len(row) > hl:
                hl = len(row)
                hid = idx

        mincol = []
        if len(rows) == 0:
            return

        for head in rows[hid]:
            mincol.append(len(head))

        for row in rows:
            for idx,head in enumerate(row):
                col = str(row[head])
                l = mincol[idx]
                mincol[idx] = max(len(col),l)

        for idx,head in enumerate(rows[hid]):
            print("{}".format(head.ljust(mincol[idx]+2)),end="")
        print("")

        for row in rows:
            for idx,head in enumerate(row):
                col = str(row[head])
                print("{}".format(col.ljust(mincol[idx]+2)),end="")
            print("")

    def getPricePercentDif(self, price1, price2):
        price1 = float(price1)
        price2 = float(price2)
        return ((price1 - price2) * 100) / price1

    def getPriceFromPercent(self, price, percent ):
        return (price * percent) + price

    def order_summary(self, currency, details=False):
        orders = []
        for idx, order in enumerate(reversed(self.history)):
            if order["Exchange"].endswith("-{}".format(currency)):
                if "OrderUuid" in order:
                    del order['OrderUuid']
                if "ConditionTarget" in order:
                    del order['ConditionTarget']
                if "Commission" in order:
                    del order['Commission']
                if "IsConditional" in order:
                    del order['IsConditional']
                if "TimeStamp" in order:
                    del order['TimeStamp']
                if "ImmediateOrCancel" in order:
                    del order['ImmediateOrCancel']
                if "Condition" in order:
                    del order['Condition']
                orders.append(order)

        if details:
            return orders

        qty = 0
        olist = []
        for order in orders:
            q = order["Quantity"] - order["QuantityRemaining"]
            if order["OrderType"] == "LIMIT_BUY":
                olist.append({'market': order["Exchange"], 'qty': q, "price": order["PricePerUnit"]})
                qty += q
            elif order["OrderType"] == "LIMIT_SELL":
                qty -= q
                for buy in olist:
                    if buy['qty'] > q:
                        buy['qty'] -= q
                        q = 0
                    else:
                        q = q - buy['qty']
                        buy['qty'] = 0


        markets = {}

        for order in olist:
            if order['qty'] > 0:
                market = order["market"]
                if market not in markets:
                    markets[market] = self.buildWatcher(order={
                        "market": market,
                        "price": order["price"],
                        "total": order["price"] * order["qty"],
                        "qty": order["qty"],
                        "orders": 1
                        })
                else:
                    markets[market]["price"] += order["price"]
                    markets[market]["total"] += order["price"] * order["qty"]
                    markets[market]["qty"] += order["qty"]
                    markets[market]["orders"] += 1

        for market in markets:
            tick = self.bittrex.public_get_ticker(market).data["result"]
            avgPrice = markets[market]["total"] / markets[market]["qty"]
            markets[market]['price'] = avgPrice
            # markets[market]['price'] /= markets[market]['orders']
            markets[market]['last'] = "{:.08f}".format(tick['Last'])
            markets[market]['bid'] = "{:.08f}".format(tick['Bid'])
            markets[market]['ask'] = "{:.08f}".format(tick['Ask'])
            avgPrice = markets[market]["total"] / markets[market]["qty"]
            # markets[market]['avg'] = avgPrice
            markets[market]['dif'] = "{:.02f}".format(self.getPricePercentDif( tick["Last"], avgPrice))
            markets[market]['total'] = markets[market]['qty'] * tick["Last"]
            markets[market]['exchange'] = "bittrex"

        return markets

    def buildWatcher(self, order):
        obj = {
            "market": "",
            "price": 0,
            "qty": 0,
            "orders": 0,
            "last": 0,
            "bid": 0,
            "ask": 0,
            "dif": 0,
            "total": 0,
        }
        obj.update(order)
        return obj

    def cancelOrder(self,orderId):
        mc = self.bittrex.market_cancel(orderId)
        return mc.data["success"]

    def parsePending(self):
        if self.pendingorders is None:
            self.refresh()

        out = []
        for order in self.pendingorders:
            out.append({
               "oid": order["OrderUuid"],
               "exchange": order["Exchange"],
               "type": order["OrderType"],
               "qty": order["Quantity"],
               "remaining": order["QuantityRemaining"],
               "Limit": "{:.08f}".format(order["Limit"]),
               "Openend": order["Opened"],
               "Closed": order["Closed"],
               #"Cancelled": order["ImmediateOrCancelled"]
               })

        return out

    def parse(self, market=None):
        if self.bal is None:
            self.refresh()

        acc = []
        rows = []
        for account in self.bal:
            if account['Balance'] > 0:
                if account["Currency"] not in ["USDT", "BTC"] and \
                   (market is None or market in account["Currency"].lower()):
                    summary = self.order_summary(account["Currency"],
                                                 market is not None)
                    rows.append(summary)
                    acc.append(account)

        if market is not None:
            return rows[0]

        out = []
        for row in rows:
            for market in row:
                m = row[market]
                out.append(m)

        return out
Exemple #3
0
class BittrexManager(ExchangeManager):
    def __init__(self, config={}):
        ExchangeManager.__init__(self, "BTRX", config)
        self.api = Bittrex()
        self.balance = None
        self.log = logging.getLogger('crypto')

    def processOrder(self, order):
        order.setExchange(self.getName())
        self.log.info("bittrex exchange processing order")
        if order.rate != order.MARKET:
            if order.order_type == order.SELL:
                r = self.api.market_selllimit(order.market, order.qty,
                                              order.rate).getData()
            elif order.order_type == order.BUY:
                r = self.api.market_buylimit(order.market, order.qty,
                                             order.rate).getData()

            if r["success"]:
                order.ref_id = r["result"]["uuid"]
                order.status = order.OPEN
            else:
                order.status = order.ERROR

            order.meta["api"] = {"create": r}
            res = order.save()
            self.log.info("save results {}".format(res))
            return Result(r["success"], r["message"], r["result"])
        else:
            return Result.fail("Market orders not allowed on bittrex")

    def syncOrder(self, order):
        if order.status < order.TERMINATED_STATE:
            status = order.status
            results = self.api.account_get_order(order.ref_id)
            data = results.getData()
            if data["success"]:
                res = data["result"]
                if res["CancelInitiated"]:
                    order.status = order.CANCELLED
                elif not res["IsOpen"] and res["Type"] == "LIMIT_SELL":
                    order.status = order.COMPLETED
                elif not res["IsOpen"] and res["Type"] == "LIMIT_BUY":
                    order.status = order.FILLED
                elif res["IsOpen"] and not res["Quantity"] > res[
                        "QuantityRemaining"] and order.status != order.PARTIAL_FILL:
                    order.status = order.PARTIAL_FILL

                if status != order.status or "state" not in order.meta["api"]:
                    self.log.info("found updates to order {}".format(
                        order.ref_id))
                    order.meta["api"]["state"] = data
                    order.save()
                    if order.status == order.COMPLETED:  # and order.order_type == Order.SELL:
                        self.log.info(
                            "looking for associated order: {}".format(
                                order.assoc_id))
                        assocorder = Order.findById(order.assoc_id)
                        if assocorder.isOk():
                            aorder = assocorder.data["results"][0]
                            aorder.status = Order.COMPLETED
                            self.log.info("found associated order {}".format(
                                aorder.ref_id))
                            #instead get this rate from the api results...
                            aorder.meta["sold_at"] = data["result"][
                                'PricePerUnit']
                            aorder.assoc_id = order.pkey  #data["result"]['PricePerUnit']
                            res = aorder.save()
                            self.log.info(
                                "saved associated order {}".format(res))

                    return True

    def getBalance(self, currency):
        if self.balance is None:
            self.getBalances()

        currency = currency.upper()
        if currency in self.balance:
            return self.balance[currency]["Available"]

    def getBalances(self):
        results = self.api.account_get_balances().getData()
        if results["success"]:
            self.balance = {}
            for c in results["result"]:
                self.balance[c["Currency"]] = c

        return self.balance
Exemple #4
0
class HoldingMonitor(object):
    def __init__(self):

        self.log = logging.getLogger('crypto')
        #a list of all active investments
        self.holdings = []

        #a record of all active trades
        self.trades = []

        self.budget = 0

        #a list of indicators used validate trade positions
        self.indicators = ["macd", "bbands"]

        #in memory data store for each market's analysis
        self.datastore = {}

        self.exchange = Bittrex()

        #candlestick chart data
        self.cs = None

        self.framesize = "5m"
        self.timeframe = "24h"

        self.settings = {"limit": 0.02, "profit": 0.03, "trailing_stop": 0.01}

    def setMarket(self, market):
        self.process(market)

    def setIndicators(self, indicators):
        self.indicators = indicators

    def setTimeframe(self, timeframe, framesize):
        self.timeframe = timeframe
        self.framesize = framesize

    def process(self, currency):
        if not currency in self.datastore:
            self.datastore[currency] = {}

        self.datastore[currency] = self.checkMarketStatus(currency)
        return self.datastore[currency]

    def checkMarkets(self, marketlist=None):

        if marketlist is None:
            marketlist = self.holdings

        for currency in marketlist:
            if not currency in self.datastore:
                self.datastore[currency] = {}

            self.datastore[currency] = self.checkMarketStatus(currency)

        return self.datastore

    def analyzeIndicators(self, currency, bot):

        analysis = self.datastore[currency]
        market = CoinCalc.getInstance().get_market(currency)
        idata = []

        self.datastore[currency]["indicatordata"] = {}
        for indicator in analysis:
            if "analysis" in analysis[indicator]:
                self.log.info(analysis[indicator])
                res = analysis[indicator]["analysis"]
                idata += [res]
                self.datastore[currency]["indicatordata"][
                    res["name"]] = analysis[indicator]

        botres = bot(self)
        action = botres["signal"]
        cur_price = botres["cur_price"]
        limitorder = botres["limitorder"]

        return {
            "market": market,
            "currency": currency,
            "cs_time": self.cs["time"][-1],
            "signal": action,
            "limitorder": limitorder,
            "indicators": idata
        }

    def checkMarketStatus(self, currency, data=None):
        if data is None:
            data = self.datastore[currency]

        market = CoinCalc.getInstance().get_market(currency)
        if market:
            traderTA = Trader(market)
            self.cs = traderTA.get_candlesticks(self.timeframe, self.framesize)

            ath = 0
            for v in self.cs["high"]:
                if v > ath:
                    ath = v

            atl = 9999999
            for v in self.cs["low"]:
                if v < atl:
                    atl = v

            ret = {
                "price": {
                    "count": 0,
                    "last": self.cs["closed"][-1],
                    "open": self.cs["open"][-1],
                    "HIGH": ath,
                    "LOW": atl,
                    "time": self.cs["time"][-1],
                }
            }
            for indicator in self.indicators:
                if indicator == "macd":
                    macd = MACD(self.cs)
                    ret["macd"] = macd.get_analysis(data)
                elif indicator == "bbands":
                    bb = BBands(self.cs, timeperiod=20, nbdevup=2, nbdevdn=2)
                    ret["bbands"] = bb.get_analysis(data)

            return ret

    def buyCurrency(self, indicatordata):
        #self.log.info(indicatordata)
        currency = indicatordata["currency"]
        indicator_time = indicatordata["cs_time"]
        bid_price = indicatordata["limitorder"]
        amount = 0.1

        return self.xbuyCurrency(currency, indicator_time, bid_price, amount)

    def sellCurrency(self, indicatordata):
        return {}

    def xbuyCurrency(self, currency, indicator_time, bid_price, amount):

        for trade in self.trades:
            if trade["time"] == indicator_time and trade[
                    "currency"] == currency:
                return None

        market = CoinCalc.getInstance().get_market(currency)
        #TODO: grab this value dynamically
        trade_percent = 0.0025

        trade_cost = amount * bid_price * trade_percent
        break_even_price = trade_cost * 2 + bid_price

        # for testing purposes...
        buy_price = bid_price
        limit = buy_price - (buy_price * self.settings["limit"])
        exit = buy_price + (buy_price * self.settings["profit"])

        support = 0
        resistance = 0
        trailing_limit = 0

        buyMap = {
            "time": indicator_time,
            "currency": currency,
            "market": market,
            "desired_entry": bid_price,
            "real_entry": buy_price,
            "amount": amount,
            "trade_cost": trade_cost,
            "break_even_price": break_even_price,
            "desired_exit": exit,
            "real_exit": 0,
            "limit": limit,
            "trailing_limit": trailing_limit,
            "total_profit": 0
        }

        self.trades += [buyMap]
        return self.trades

    def analyzeTrade(self, trade):
        #buy_price = bid_price
        #limit = buy_price - (buy_price * self.settings["limit"] )
        #exit = buy_price + ( buy_price * self.settings["profit"] )

        cur_price = self.cs["closed"][-1]
        growth = ((cur_price - trade["real_entry"]) / cur_price) * 100

        trade["action"] = "hodl"
        trade["growth"] = round(growth, 2)
        trade["profit"] = (cur_price * trade["amount"]) - (
            trade["real_entry"] * trade["amount"])
        #trade[""] = 0

        return trade

    # depends on a call to self.getMarkets() to have been made to get last price data
    def analyzeTrades(self):
        tradedata = []
        for trade in self.trades:
            tradedata += [self.analyzeTrade(trade)]
        return tradedata

    def getHoldings(self):
        holdings = {}
        calc = CoinCalc.getInstance()
        bal = self.exchange.account_get_balances().getData()
        if bal and bal["success"] == True:
            for currency in bal["result"]:
                if currency["Available"] > 0:
                    holdings[currency["Currency"]] = {
                        "Market": calc.get_market(currency["Currency"]),
                        "Balance": currency["Balance"],
                        "Available": currency["Available"],
                        "Pending": currency["Pending"]
                    }

        self.holdings = holdings
        return self.holdings