def __init__(self, stratName, isLive=False): logging.debug("Initialising ExitTrade()") self.isLive = isLive self.stratName = stratName db = MongoClient("localhost", 27017)[stratName] self.transCol = db["transactionLogs"] self.currentCol = db["currentPositions"] self.pull = Pull() self.capDict = None
def __init__(self, stratName, isTest): logging.debug("Initilising ERC20TickFade") with open("%s/Pipeline/resources/%s/config.yml" % (Settings.BASE_PATH, stratName)) as configFile: self.enterParams = yaml.load(configFile)["enter"] self.coinDict = self.enterParams["assetList"] self.isTest = isTest self.p = Pull() self.coolDown = True self.oldData = {"erc": pd.DataFrame([]), "non": pd.DataFrame([])}
def __init__(self, stratName, isLive=False): self.stratName = stratName logging.debug("Initialising OpenTrade()") self.isLive = isLive self.resourcePath = "%s/Pipeline/resources/%s" % (Settings.BASE_PATH, stratName) self.db = MongoClient("localhost", 27017)[stratName] self.EU = ExchangeUtil() self.P = Position(stratName) self.pull = Pull() self.capDict = None
def test_candles(): BinanceData = Binance().getCandles(asset="LTCBTC", limit=5, interval=300, columns=["TS", "open"], lastReal=True) PullData = Pull().candles( exchange="Binance", asset="LTCBTC", limit=5, interval=300, columns=["TS", "open"], lastReal=True, ) assert PullData.equals(BinanceData) and len(PullData) != 0
def _initSingle(self, asset, exchange, testData=[]): logging.debug("Starting CheapVol._initSingle(asset=%s)" % asset) logging.debug("1 second sleep to avoid rate limiters") time.sleep(1.5 if not self.isTest else 0) try: pullData = (Pull( emailOnFailure=False if self.isTest else True).candles( asset="%sBTC" % asset, exchange=exchange, limit=max( self.enterParams["periodsMA"], self.enterParams["periodsVolLong"], ) + 1, interval=self.enterParams["granularity"], ) if len(testData) == 0 else testData) priceList = list( pullData["close"])[-self.enterParams["periodsMA"]:] volList = list( pullData["volume"])[-self.enterParams["periodsVolLong"]:] if (len(priceList) == self.enterParams["periodsMA"] and len(volList) == self.enterParams["periodsVolLong"]): self.col.insert_one({ "asset": asset, "price": priceList, "vol": volList, "isLive": False, }) return True else: logging.info("Not enough data for asset: %s" % asset) except IndexError: logging.warning("Failure on asset: %s" % asset) return False
def before(self, testData=None): """ Runs before CheapVol on each asset and updates the mongo collection """ logging.debug("Starting CheapVol.before()") newPA = {} delistDict = {} # using reversed to keep exchange priority for exchange in reversed(self.exchangeList): newPA.update( self._getPADict( exchange=exchange) if not self.isTest else testData) delistDict.update(Pull().getDepositStatus( exchange=exchange)) if not self.isTest else {} for assetDict in list(self.col.find()): assetDict["price"] = assetDict["price"][1:] + [ newPA[assetDict["asset"]]["price"] ] assetDict["vol"] = assetDict["vol"][1:] + [ newPA[assetDict["asset"]]["vol"] ] assetDict["isLive"] = (delistDict[assetDict["asset"]] if not self.isTest else True) assetDict.pop("_id", None) self.col.find_one_and_replace({"asset": assetDict["asset"]}, assetDict) logging.debug("Finished CheapVol.before()")
def before(): CCD.create() col.insert_one(posDataMain) params = { "isLive": False, "exit": { "bolStd": 2, "granularity": 7200, "name": "ProfitRun", "maPeriods": 5, "closePeriods": 5, "stdDict": { "up": 1, "down": 0.5 }, "exchange": "Binance", }, } with open("%s/%s/config.yml" % (Settings.BASE_PATH, resPath), "w") as configFile: yaml.dump(params, configFile) PR = ProfitRun(stratName="testExit", isTest=True) E = Exit(stratName="testExit", isTest=True) P = Pull() return PR, E, P
def getTradesDiff(self, asset, exchange): logging.debug("Starting OrderBookDepth.getTradesDiff") vals = Pull().getTrades( asset=asset, exchange=exchange, limit=self.enterParams["numTrades"], maxTime=self.enterParams["period"], ) if len(vals) != 0: vL = len(vals) meanVal = round(float(np.mean(vals["Qty"]))) diff = round( sum(vals[vals["Buy/Sell"] == "b"]["Qty"]) - sum(vals[vals["Buy/Sell"] == "s"]["Qty"]) ) return ( [ diff - (vL / diffVal) * meanVal for diffVal in self.enterParams["diffVals"] ] + [diff] + [ diff + (vL / diffVal) * meanVal for diffVal in self.enterParams["diffVals"] ] ) else: return -1
def _getPADict(self, exchange): logging.debug("Starting CheapVol._getPADict()") startTS = int(time.time() - self.enterParams["granularity"]) dateStart = datetime.fromtimestamp(startTS).strftime( "%Y-%m-%dT%H:%M:%S.000Z") return Pull().getPriceAction(exchange=exchange, startDate=dateStart, baseAsset="BTC")
def __init__(self, stratName, isTest=False, testAssets=None): logging.debug("Initialising Enter()") self.compPath = "%s/Pipeline/resources/%s" % (Settings.BASE_PATH, stratName) self.stratName = stratName self.isTest = isTest with open("%s/config.yml" % self.compPath) as stratFile: self.config = yaml.load(stratFile) self.assetList = Select(stratName).assets() if not isTest else testAssets self.enterStrat = eval(self.config["enter"]["name"])( stratName=stratName, assetList=self.assetList, isTest=isTest ) self.OT = ( OpenTrade(stratName=stratName, isLive=self.config["isLive"]) if not isTest else None ) self.pull = Pull() self.col = MongoClient("localhost", 27017)[stratName]["currentPositions"]
def getAssets(self): logging.debug("Starting AllNomics.getAssets") logging.debug("Exchanges analysed: %s" % self.exchangeList) logging.debug("Base Asset: %s" % self.baseAsset) assetList = [] for exchange in self.exchangeList: logging.debug("Starting exchange: %s" % exchange) if self.baseAsset == "BTC": tmpListNomics = Pull().BTCAssets(exchange="Nomics", exchange_=exchange) tmpListEx = Pull().BTCAssets(exchange=exchange, justQuote=True) tmpList = list(set(tmpListNomics) & set(tmpListEx)) addedAssets = ([ val.lower() for val in np.array(assetList)[:, 0] ] if len(assetList) != 0 else []) assetList += [(asset, exchange) for asset in tmpList if asset.lower() not in addedAssets] logging.debug("Ending All.getAssets") logging.debug("Assetlist length: %s" % len(assetList)) return assetList
class AccountUtil: def __init__(self, exchange, isTest=False): logging.debug("Initialising AccountUtil()") self.exchange = exchange self.isTest = isTest self.P = Pull() def _calcValue(self, accountDetails): logging.debug("Starting AccountUtil._calcValue") value = 0 for coin in [c for c in list(accountDetails) if c != "BTC"]: value += accountDetails[coin] * ( self.P.assetPrice( exchange=self.exchange, asset="%sBTC" % coin, dir="sell" ) if not self.isTest else self.isTest[coin] ) return value def getValue(self, initCapital, isTest=False): logging.debug("Starting AccountValue.getValue") capDict = {"initialCapital": initCapital} accountDetails = ( self.P.getAccount(exchange=self.exchange) if not isTest else isTest ) capDict["liquidCurrent"] = round(accountDetails["BTC"], 8) capDict["paperCurrent"] = round( capDict["liquidCurrent"] + self._calcValue(accountDetails), 8 ) capDict["paperPnL"] = round( capDict["paperCurrent"] / capDict["initialCapital"], 2 ) capDict["percentAllocated"] = round( (capDict["paperCurrent"] - capDict["liquidCurrent"]) / capDict["paperCurrent"], 2, ) return capDict
def __init__(self, stratName, isTest=False): logging.debug("Initializing Exit()") with open("%s/Pipeline/resources/%s/config.yml" % (Settings.BASE_PATH, stratName)) as stratFile: self.config = yaml.load(stratFile) self.stratName = stratName self.exitStrat = (eval(self.config["exit"]["name"])( stratName=stratName, isTest=isTest) if "statArb" not in self.config.keys() else None) self.col = MongoClient("localhost", 27017)[stratName]["currentPositions"] self.pull = Pull() self.updatePosition = UpdatePosition(stratName) self.exitTrade = ExitTrade(stratName, isLive=self.config["isLive"])
def _isVol(self): """ True if vol_1d/vol_1m < maxVolCoef """ data = Pull().candles( exchange="Nomics", asset="BTC", interval="1h", columns=None, lastReal=None, limit=None, ) vol = np.nanmean(data["volume"].iloc[-24:].astype(float)) / np.nanmean( data["volume"].astype(float)) logging.debug("Vol: %s" % vol) return vol < self.enterParams["maxVolCoef"]
def createAssetList(self): tickerData = { val["symbol"]: { "vol": float(val["quoteVolume"]), "tradeCount": val["count"], "baseVol": float(val["volume"]), } for val in Pull().getTickerStats(exchange="Binance") if "BTC" in val["symbol"] } coinList = [] base = tickerData["BTCUSDT"]["baseVol"] for coin in [c for c in list(tickerData) if c != "BTCUSDT"]: if (tickerData[coin]["tradeCount"] > self.params["minTrades"] and self.params["minVol"] * base < tickerData[coin]["vol"] < self.params["maxVol"] * base): coinList.append({"asset": coin, "exchange": "Binance"}) self.assetCol.insert_many(coinList)
def run(self, asset, exchange, testData=None): logging.debug("Starting OrderBookDepth.run") tradeDiff = self.getTradesDiff(asset=asset, exchange=exchange) priceList = [] if tradeDiff != -1: orderBook = Pull().getOrderBook( exchange=exchange, asset=asset, limit=self.enterParams["bookDepth"] ) for tradeQty in tradeDiff: priceList.append(self.walkDown(orderBook, tradeQty)) price_ = round(float(np.mean(priceList)), 8) pDiff = round(price_ / orderBook["bids"][0][1], 8) if pDiff > 1: logging.debug("Asset: %s, pDiff: %s" % (asset, pDiff)) if pDiff > self.enterParams["enterPercent"]: return True else: return False else: logging.debug("Data is incomplete") return False
def getAssets(self): logging.debug("Starting All.getAssets") logging.debug("Exchanges analysed: %s" % self.exchangeList) logging.debug("Base Asset: %s" % self.baseAsset) assetList = [] for exchange in self.exchangeList: logging.debug("Starting exchange: %s" % exchange) if self.baseAsset == "BTC": tmpList = Pull().BTCAssets(exchange=exchange) addedAssets = ( [val.lower() for val in np.array(assetList)[:, 0]] if len(assetList) != 0 else [] ) assetList += [ (asset, exchange) for asset in tmpList if asset.lower() not in addedAssets ] logging.debug("Ending All.getAssets") return assetList
class ERC20TickFade: """ Buy ETHUSD, Sell BTCUSD when erc20tick > enterVal Config Requirements: - enterVal - assetList = { 'erc20': [], 'non': [] } - maxVolCoef """ def __init__(self, stratName, isTest): logging.debug("Initilising ERC20TickFade") with open("%s/Pipeline/resources/%s/config.yml" % (Settings.BASE_PATH, stratName)) as configFile: self.enterParams = yaml.load(configFile)["enter"] self.coinDict = self.enterParams["assetList"] self.isTest = isTest self.p = Pull() self.coolDown = True self.oldData = {"erc": pd.DataFrame([]), "non": pd.DataFrame([])} def _getTick(self, type): logging.debug("Starting ERC20TickArb._getTick()") newPrices = self.p.getPriceList(coinList=self.coinDict[type]) logging.debug("Pulled new prices for type: %s" % type) if len(self.oldData[type]) != 0: logging.debug("Calculating tick value") tick = sum([ 1 if val > 0 else -1 if val < 0 else 0 for val in list(newPrices["price"] - self.oldData[type]["price"]) ]) logging.debug("Ending ERC20TickArb._getTick()") logging.debug("Tick Val: %s" % tick) return tick else: logging.debug("Creating old data") self.oldData[type] = newPrices logging.debug("Ending ERC20TickArb._getTick()") return 0 def _isVol(self): """ True if vol_1d/vol_1m < maxVolCoef """ data = Pull().candles( exchange="Nomics", asset="BTC", interval="1h", columns=None, lastReal=None, limit=None, ) vol = np.nanmean(data["volume"].iloc[-24:].astype(float)) / np.nanmean( data["volume"].astype(float)) logging.debug("Vol: %s" % vol) return vol < self.enterParams["maxVolCoef"] def run(self): logging.debug("Starting ERC20TickFade.run()") logging.debug("IsCoolDown: %s" % self.coolDown) if self._isVol() and not self.coolDown: tickSum = self._getTick(type="erc") - self._getTick(type="non") if tickSum > self.enterParams["enterVal"]: self.coolDown = True return 1 elif tickSum < -self.enterParams["enterVal"]: self.coolDown = True return -1 else: return 0 else: logging.debug("Creating oldData") self.coolDown = False _ = self._getTick(type="erc") _ = self._getTick(type="non")
def __init__(self, exchange, isTest=False): logging.debug("Initialising AccountUtil()") self.exchange = exchange self.isTest = isTest self.P = Pull()
class Enter: def __init__(self, stratName, isTest=False, testAssets=None): logging.debug("Initialising Enter()") self.compPath = "%s/Pipeline/resources/%s" % (Settings.BASE_PATH, stratName) self.stratName = stratName self.isTest = isTest with open("%s/config.yml" % self.compPath) as stratFile: self.config = yaml.load(stratFile) self.assetList = Select(stratName).assets() if not isTest else testAssets self.enterStrat = eval(self.config["enter"]["name"])( stratName=stratName, assetList=self.assetList, isTest=isTest ) self.OT = ( OpenTrade(stratName=stratName, isLive=self.config["isLive"]) if not isTest else None ) self.pull = Pull() self.col = MongoClient("localhost", 27017)[stratName]["currentPositions"] def run(self): try: logging.info("Starting Enter.run: %s" % datetime.now()) startTime = time.time() openList = [] currentPositions = [ val["assetName"] for val in list(self.col.find({}, {"assetName": 1})) ] self.OT.initRun() if not self.isTest else None self.enterStrat.before() if not self.isTest else None for asset, exchange in [ val for val in self.assetList if "%sBTC" % val[0] not in currentPositions ]: logging.debug("Starting asset: %s" % asset) if self.enterStrat.run(asset): logging.info("Entering trade: %s" % asset) openPrice = ( self.pull.assetPrice( exchange=exchange, asset="%sBTC" % asset, dir="buy" ) if not self.isTest else 1 ) if openPrice != -1: openList.append(asset) self.OT.open( assetVals=("%sBTC" % asset, exchange, openPrice) ) if not self.isTest else None self.OT.updateBooks() if not self.isTest else None logging.info( "Ending Enter run. Took: %s seconds" % round(time.time() - startTime) ) logging.info("%s assets analysed" % len(self.assetList)) logging.info( "Entering trades: \n %s" % openList if len(openList) != 0 else "0 trades entered" ) return openList if self.isTest else None except Exception as e: EmailUtil(strat=self.stratName).errorExit( file=self.stratName, funct="Enter.run()", message=f"Error message: {e}, \n Asset: {asset}", ) raise Exception
def before(): P = Pull() CCD.create() posDataInit = { "assetName": "ADABTC", "openPrice": 0.0000158, "currentPrice": 9, "periods": 0, "positionSize": 0.4995, "paperSize": 0.4995, "TSOpen": 1534711395, "exchange": "Binance", } posDataMain = { "assetName": "ETHBTC", "openPrice": 0.0000158, "currentPrice": 10, "periods": 0, "hitPrice": 11, "positionSize": 0.4995, "paperSize": 0.4995, "TSOpen": 1534711395, "sellPrice": 9, "exchange": "Binance", } posDataPeriods = { "assetName": "LTCBTC", "openPrice": 0.0000158, "currentPrice": 0.0000158, "periods": 6, "sellPrice": 9, "positionSize": 0.4995, "paperSize": 0.4995, "TSOpen": 1534711395, "hitPrice": 11, "exchange": "Binance", } updatePosData = pd.DataFrame(data=[[10], [9], [8], [11], [7]], columns=["close"]) col.insert_many([posDataMain, posDataInit, posDataPeriods]) params = { "exit": { "bolStd": 2, "granularity": 7200, "name": "ProfitRun", "maPeriods": 5, "closePeriods": 5, "stdDict": { "up": 1, "down": 0.5 }, } } with open("%s/%s/config.yml" % (Settings.BASE_PATH, resPath), "w") as configFile: yaml.dump(params, configFile) PR = ProfitRun("testProfitRun", isTest=True) return ( PR, P, { "main": posDataMain, "init": posDataInit, "periods": posDataPeriods }, updatePosData, )
class OpenTrade: def __init__(self, stratName, isLive=False): self.stratName = stratName logging.debug("Initialising OpenTrade()") self.isLive = isLive self.resourcePath = "%s/Pipeline/resources/%s" % (Settings.BASE_PATH, stratName) self.db = MongoClient("localhost", 27017)[stratName] self.EU = ExchangeUtil() self.P = Position(stratName) self.pull = Pull() self.capDict = None def initRun(self): with open("%s/capital.yml" % self.resourcePath) as capFile: self.capDict = yaml.load(capFile) def _getPrice(self, fills): return round( sum([float(val["price"]) * float(val["qty"]) for val in fills]) / sum([float(val["qty"]) for val in fills]), 8, ) def open(self, assetVals): logging.debug("Starting OpenTrade.open") # assetVals = (name, exchange, price) capAllocated = self.P.getSize(asset=assetVals[0]) posSize = capAllocated * (1 - self.EU.fees(exchange=assetVals[1])) if not self.isLive: openDict = { "assetName": assetVals[0], "openPrice": assetVals[2], "currentPrice": assetVals[2], "periods": 0, "positionSize": posSize, "paperSize": posSize, "TSOpen": round(time.time()), "exchange": assetVals[1], } else: try: quantity = round(capAllocated / assetVals[2], 2) orderDict = self.pull.makeTrade( exchange=assetVals[1], asset=assetVals[0], quantity=np.floor(quantity), dir="BUY", ) buyPrice = self._getPrice(orderDict["fills"]) openDict = { "assetName": assetVals[0], "openPrice": buyPrice, "currentPrice": buyPrice, "periods": 0, "positionSize": float(orderDict["cummulativeQuoteQty"]), "posSizeBase": float(orderDict["executedQty"]), "TSOpen": round(time.time()), "exchange": assetVals[1], "clientOrderId": orderDict["clientOrderId"], } except KeyError as e: EmailUtil(strat=self.stratName).errorExit( file=self.stratName, funct="Enter.runNorm()", message=e) logging.error("orderDict: %s" % orderDict) raise Exception( "Failed with error message: %s and assetVals: %s" % (e, assetVals)) self.db["currentPositions"].insert_one(openDict) self.capDict["paperCurrent"] -= round( capAllocated - openDict["positionSize"], 6) self.capDict["liquidCurrent"] -= capAllocated def updateBooks(self): logging.debug("Starting OpenTrade.updateBooks()") if not self.isLive: self.capDict["percentAllocated"] = round( 1 - self.capDict["liquidCurrent"] / self.capDict["paperCurrent"], 3) self.capDict["paperPnL"] = round( self.capDict["paperCurrent"] / self.capDict["initialCapital"], 3) else: # **TODO hard coding 'Binance' as whole capDict system will need to change to capListDict when adding multiple self.capDict = AccountUtil(exchange="Binance").getValue( initCapital=self.capDict["initialCapital"]) with open("%s/capital.yml" % self.resourcePath, "w") as capFile: yaml.dump(self.capDict, capFile)
class ExitTrade: def __init__(self, stratName, isLive=False): logging.debug("Initialising ExitTrade()") self.isLive = isLive self.stratName = stratName db = MongoClient("localhost", 27017)[stratName] self.transCol = db["transactionLogs"] self.currentCol = db["currentPositions"] self.pull = Pull() self.capDict = None def initBooks(self): logging.debug("Starting ExitTrade.initBooks") with open( "%s/Pipeline/resources/%s/capital.yml" % (Settings.BASE_PATH, self.stratName) ) as capFile: self.capDict = yaml.load(capFile) logging.debug("Ending ExitTrade.initBooks") def _getPrice(self, fills): return round( sum([float(val["price"]) * float(val["qty"]) for val in fills]) / sum([float(val["qty"]) for val in fills]), 8, ) def exit(self, positionDict, currentPrice): logging.debug("Starting ExitTrade.exit") fees = ExchangeUtil().fees(exchange=positionDict["exchange"]) dir = positionDict["dir"] if "dir" in positionDict.keys() else "buy" leverage = positionDict["leverage"] if "leverage" in positionDict.keys() else 1 exitPositionSize = ( round( (currentPrice / float(positionDict["openPrice"])) * float(positionDict["positionSize"]) * (1 - fees), 6, ) if dir == "buy" else round( (float(positionDict["openPrice"] / currentPrice)) * float(positionDict["positionSize"]) * (1 - fees), 6, ) ) logging.debug( "Removing val from db.currentPosition & inserting into db.tranactionLog" ) self.currentCol.delete_one({"assetName": positionDict["assetName"]}) if not self.isLive: realPnL = (exitPositionSize - positionDict["positionSize"]) * leverage exitDict = { "assetName": positionDict["assetName"], "openPrice": round(float(positionDict["openPrice"]), 8), "closePrice": round(currentPrice, 8), "percentPnL": round(currentPrice / positionDict["openPrice"] - 1, 6), "TSOpen": positionDict["TSOpen"], "TSClose": round(time.time()), "periods": positionDict["periods"] + 1, "positionSize": positionDict["positionSize"], "realPnL": round(realPnL, 8), } else: orderDict = self.pull.makeTrade( exchange=positionDict["exchange"], asset=positionDict["assetName"], quantity=positionDict["posSizeBase"], dir="SELL", ) realPnL = float(orderDict["cummulativeQuoteQty"]) - float( positionDict["positionSize"] ) closePrice = self._getPrice(orderDict["fills"]) exitDict = { "assetName": positionDict["assetName"], "openPrice": round(positionDict["openPrice"], 8), "hitPrice": round(positionDict["hitPrice"], 8), "sellPrice": round(positionDict["sellPrice"], 8), "closePrice": closePrice, "percentPnL": round(closePrice / positionDict["openPrice"] - 1, 6), "TSOpen": positionDict["TSOpen"], "TSClose": round(time.time()), "periods": positionDict["periods"] + 1, "positionSize": positionDict["positionSize"], "realPnL": round(realPnL, 8), } self.transCol.insert_one(exitDict) self.capDict["liquidCurrent"] += exitPositionSize logging.debug("Ending ExitTrade.run") def paperValue(self): logging.debug("Starting ExitTrade.paperValue") return sum([val["paperSize"] for val in list(self.currentCol.find())]) def closeOutBooks(self): logging.debug("Starting ExitTrade.closeOutBooks") if not self.isLive: self.capDict["paperCurrent"] = round( self.capDict["liquidCurrent"] + self.paperValue(), 4 ) self.capDict["percentAllocated"] = round( 1 - self.capDict["liquidCurrent"] / self.capDict["paperCurrent"], 3 ) self.capDict["paperPnL"] = round( self.capDict["paperCurrent"] / self.capDict["initialCapital"], 3 ) self.capDict["liquidCurrent"] = round(self.capDict["liquidCurrent"], 4) else: # **TODO hard coding 'Binance' as whole capDict system will need to change to capListDict when adding multiple self.capDict = AccountUtil(exchange="Binance").getValue( initCapital=self.capDict["initialCapital"] ) with open( "%s/Pipeline/resources/%s/capital.yml" % (Settings.BASE_PATH, self.stratName), "w", ) as capFile: yaml.dump(self.capDict, capFile) logging.debug("Ending ExitTrade.closeOutBooks")