def get_all_orders(self): # here we want to get the value of user (i.e. ?user=some-value) limit = 50 if not request.args.get("limit") else int( request.args.get("limit")) offset = (0 if not request.args.get("offset") else int( request.args.get("offset"))) self.pages = self.app.db.orders.count() status = request.args.get("status", None) startTime = (int(request.args.get("start-time", None)) if request.args.get("start-time") else None) # Filters args = {} if status: args["status"] = status if startTime: args["time"] = {"$gte": startTime} orders = list( self.app.db.orders.find(args).sort([("updateTime", -1) ]).skip(offset).limit(limit)) if orders: resp = jsonResp({"data": orders, "pages": self.pages}, 200) else: resp = jsonResp({"message": "Orders not found!"}, 200) return resp
def get(self): resp = jsonResp({"message": "Endpoint failed"}, 200) bot = list(app.db.bots.find()) if bot: resp = jsonResp({"data": bot}, 200) else: resp = jsonResp({"message": "Bots not found", "data": []}, 200) return resp
def delete(self): findId = request.view_args["id"] count = app.db.users.delete_one({"_id": ObjectId(findId)}).deleted_count if count > 0: resp = jsonResp({"message": "Successfully deleted user"}, 200) else: resp = jsonResp({"message": "Not found user, cannot delete"}, 200) return resp
def get_one(self): findId = request.view_args["id"] user = app.db.users.find_one({"_id": ObjectId(findId)}) if user: resp = jsonResp({"message": "User found", "data": user}, 200) else: resp = jsonResp({"message": "User not found", "error": 1}, 404) return resp
def get_one(self): resp = jsonResp({"message": "No bots found"}, 200) findId = request.view_args["id"] bot = app.db.bots.find_one({"_id": ObjectId(findId)}) if bot: resp = jsonResp({"message": "Bot found", "data": bot}, 200) else: resp = jsonResp({"message": "Bots not found"}, 404) return resp
def activate(self): findId = request.view_args["botId"] bot = app.db.bots.find_one({"_id": ObjectId(findId)}) if bot: order_errors = Deal(bot, app).open_deal() if isinstance(order_errors, Response): return order_errors # If error if len(order_errors) > 0: # If base order fails makes no sense to activate if "base_order_error" in order_errors[0]: resp = jsonResp( { "message": f'Failed to activate bot, {order_errors[0]["base_order_error"]}', "botId": str(findId), "error": 1 }, 200) else: resp = jsonResp( { "message": f"Failed to activate bot, {','.join(order_errors)}", "botId": str(findId), "error": 1 }, 200) return resp botId = app.db.bots.find_one_and_update( {"_id": ObjectId(findId)}, {"$set": { "active": "true" }}) if botId: resp = jsonResp( { "message": "Successfully activated bot and triggered deals with no errors", "botId": str(findId), }, 200, ) else: resp = jsonResp( { "message": "Unable to save bot", "botId": str(findId), }, 200, ) return resp else: resp = jsonResp({"message": "Bot not found", "botId": findId}, 400) return resp
def get_blacklisted(self): """ Get blacklisted symbol research data """ args = {"candlestick_signal": {"$exists": True, "$ne": None}} query = self.app.db.correlations.find(args) if query: resp = jsonResp({"error": 0, "data": query}, 200) return resp else: resp = jsonResp({"error": 1, "data": query}, 200)
def delete(self): resp = jsonResp({"message": "Bot update is not available"}, 400) findId = request.view_args["id"] delete_action = app.db.bots.delete_one({"_id": ObjectId(findId)}) if delete_action: resp = jsonResp( { "message": "Successfully delete bot", "botId": findId }, 200) else: resp = jsonResp({"message": "Bot deletion is not available"}, 400) return resp
def get_open_orders(self): timestamp = int(round(tm.time() * 1000)) url = self.open_orders params = [("timestamp", timestamp), ("recvWindow", self.recvWindow)] headers = {"X-MBX-APIKEY": self.key} # Prepare request for signing r = requests.Request(url=url, params=params, headers=headers) prepped = r.prepare() query_string = urlparse(prepped.url).query total_params = query_string # Generate and append signature signature = hmac.new(self.secret.encode("utf-8"), total_params.encode("utf-8"), hashlib.sha256).hexdigest() params.append(("signature", signature)) res = requests.get(url=url, params=params, headers=headers) handle_error(res) data = res.json() if len(data) > 0: resp = jsonResp({ "message": "Open orders found!", "data": data }, 200) else: resp = jsonResp_message("No open orders found!", 200) return resp
def get_signals(self): args = {"candlestick_signal": {"$exists": True, "$ne": None}} sort = [] if request.args.get("filter_by") == "signal_side": signal_side = {"signal_side": request.args.get("filter")} args.update(signal_side) if request.args.get("filter_by") == "signal_strength": signal_side = {"signal_strength": request.args.get("filter")} args.update(signal_side) if request.args.get("filter_by") == "candlestick_signal": signal_side = {"candlestick_signal": request.args.get("filter")} args.update(signal_side) query = self.app.db.correlations.find(args) if request.args.get("order_by") == "spread": sort = [["spread", int(request.args.get("order"))]] query.sort(sort) if request.args.get("order_by") == "price_change_24": sort = [["price_change_24", int(request.args.get("order"))]] query.sort(sort) data = list(query) resp = jsonResp({"data": data}, 200) return resp
def get_symbols(self): app = create_app() args = {"blacklisted": False} project = {"market": 1, "_id": 0} query = app.db.correlations.find(args, project) symbols_list = list(query.distinct("market")) symbols_list.sort() return jsonResp({"data": symbols_list}, 200)
def get_symbol_info(self): symbols = self._exchange_info()["symbols"] pair = request.view_args["pair"] symbol = next((s for s in symbols if s["symbol"] == pair), None) if symbol: return jsonResp({"data": symbol}, 200) else: return jsonResp_message("Pair not found", 200)
def post_blacklisted(self): args = {} set = {} data = request.json if data.get("symbol"): args["market"] = data.get("symbol") set["blacklisted"] = True set["blacklisted_reason"] = data.get("reason") query = self.app.db.correlations.find_one_and_update( args, {"$set": set}) if query: resp = jsonResp({"data": query}, 200) return resp else: resp = jsonResp({"error": 1, "data": query}, 200)
def ticker_24(self): url = self.ticker24_url symbol = request.view_args["symbol"] params = {"symbol": symbol} res = requests.get(url=url, params=params) handle_error(res) data = res.json() resp = jsonResp({"data": data}, 200) return resp
def edit(self): data = request.json findId = request.view_args["id"] self.defaults.update(data) self.defaults["safety_orders"] = data["safety_orders"] botId = app.db.bots.update_one({"_id": ObjectId(findId)}, {"$set": self.defaults}, upsert=False) if botId.acknowledged: resp = jsonResp( { "message": "Successfully updated bot", "botId": findId }, 200) else: resp = jsonResp({"message": "Failed to update bot"}, 400) return resp
def create(self): data = request.json data["name"] = (data["name"] if data["name"] != "" else f"{data['pair']}-{date.today()}") self.defaults.update(data) self.defaults["safety_orders"] = data["safety_orders"] botId = app.db.bots.save(self.defaults, {"$currentDate": { "createdAt": "true" }}) if botId: resp = jsonResp( { "message": "Successfully created new bot", "botId": str(botId) }, 200) else: resp = jsonResp({"message": "Failed to create new bot"}, 400) return resp
def deactivate(self): """ Deactivation involves - Closing all deals (opened orders) - Selling all assets in the market - Finally emptying the deals array in the bot - After above actions succeed, update the DB with all these changes The bot is kept for archive purposes """ resp = jsonResp({"message": "Bot deactivation is not available"}, 400) findId = request.view_args["botId"] bot = app.db.bots.find_one({"_id": ObjectId(findId)}) if bot: # Close deals and sell everything dealId = Deal(bot, app).close_deals() # If error if isinstance(dealId, Response): resp = dealId return resp if dealId: bot["active"] = "false" bot["deals"] = [] botId = app.db.bots.update_one( {"_id": ObjectId(findId)}, {"$set": { "deals": [], "active": "false" }}, ) if botId: resp = jsonResp( { "message": "Successfully deactivated bot!", "data": bot }, 200) else: resp = jsonResp({"message": "Bot not found", "botId": findId}, 400) return resp
def required_field_validation(self, data, key): if key in data: return data[key] else: resp = jsonResp( { "message": "Validation failed {} is required".format(key), "botId": data["_id"], }, 400, ) return resp
def sell_gbp_balance(self): """ To sell GBP e.g.: - BNBGBP market buy BNB with GBP """ pair = self.active_bot["pair"] market = self.find_quoteAsset(pair) new_pair = f"{market}GBP" bo_size = self.active_bot["base_order_size"] book_order = Book_Order(new_pair) price = float(book_order.matching_engine(False, bo_size)) # Precision for balance conversion, not for the deal qty_precision = -( Decimal(str(self.lot_size_by_symbol(new_pair, "stepSize"))) .as_tuple() .exponent ) price_precision = -( Decimal(str(self.price_filter_by_symbol(new_pair, "tickSize"))) .as_tuple() .exponent ) qty = round_numbers( float(bo_size), qty_precision, ) if price: order = { "pair": new_pair, "qty": qty, "price": supress_notation(price, price_precision), } res = requests.post(url=self.bb_buy_order_url, json=order) else: # Matching engine failed - market order order = { "pair": new_pair, "qty": qty, } res = requests.post(url=self.bb_buy_market_order_url, json=order) if isinstance(handle_error(res), Response): resp = jsonResp( { "message": f"Failed to buy {pair} using GBP balance", "botId": str(self.active_bot["_id"]), }, 200, ) return resp return
def decorated(*args, **kwargs): access_token = request.headers.get("AccessToken") try: data = jwt.decode(access_token, os.environ["SECRET_KEY"]) except Exception as e: return jsonResp( { "message": "Token is invalid", "exception": str(e) }, 401) return f(*args, **kwargs)
def get_balances_btc(self): data = self.request_data()["balances"] df = pd.DataFrame(data) df["free"] = pd.to_numeric(df["free"]) df["asset"] = df["asset"].astype(str) df.drop("locked", axis=1, inplace=True) df.reset_index(drop=True, inplace=True) # Get table with > 0 balances = df[df["free"] > 0.000000].to_dict("records") data = {"total_btc": 0, "balances": []} for b in balances: symbol = self.find_market(b["asset"]) market = self.find_quoteAsset(symbol) rate = 0 if b["asset"] != "BTC": rate = self.get_ticker_price(symbol) if "locked" in b: qty = b["free"] + b["locked"] else: qty = b["free"] btc_value = float(qty) * float(rate) # Non-btc markets if market != "BTC" and b["asset"] != "USDT": x_rate = self.get_ticker_price(market + "BTC") x_value = float(qty) * float(rate) btc_value = float(x_value) * float(x_rate) # Only tether coins for hedging if b["asset"] == "USDT": rate = self.get_ticker_price("BTCUSDT") btc_value = float(qty) / float(rate) else: if "locked" in b: btc_value = b["free"] + b["locked"] else: btc_value = b["free"] data["total_btc"] += btc_value assets = {"asset": b["asset"], "btc_value": btc_value} data["balances"].append(assets) # filter out empty # Return response resp = jsonResp(data, 200) return resp
def login(self): data = request.json email = data["email"].lower() user = app.db.users.find_one({"email": email}) if user: verify = pbkdf2_sha256.verify(data["password"], user["password"]) if verify: access_token = encodeAccessToken(user["password"], user["email"]) app.db.users.update_one( {"_id": user["_id"]}, { "$set": { "access_token": access_token, "last_login": nowDatetimeUTC(), } }, ) resp = jsonResp( { "_id": user["_id"], "email": user["email"], "access_token": access_token, "error": 0 }, 200, ) return resp else: resp = jsonResp({"message": "Password verification failed"}, 200) return resp else: resp = jsonResp({"message": "Credentials are incorrect", "error": 1}, 200) return resp
def get(self): for thread in threading.enumerate(): if thread.name == "market_updates_thread": if thread._target.__self__.interval != self.interval: thread._target.__self__.markets_streams.close() market_update_thread() trace = self.candlestick_trace() ma_100, ma_25, ma_7 = self.bollinguer_bands() resp = jsonResp( { "trace": [trace, ma_100, ma_25, ma_7], "interval": self.interval }, 200) return resp
def get_raw_balance(self): """ Unrestricted balance """ data = self.request_data()["balances"] df = pd.DataFrame(data) df["free"] = pd.to_numeric(df["free"]) df["locked"] = pd.to_numeric(df["locked"]) df["asset"] = df["asset"].astype(str) # Get table with > 0 balances = df[(df["free"] > 0) | (df["locked"] > 0)].to_dict("records") # filter out empty # Return response resp = jsonResp(balances, 200) return resp
def get_pnl(self): current_time = datetime.now() days = 7 if "days" in request.args: days = int(request.args["days"]) start = current_time - timedelta(days=days) dummy_id = ObjectId.from_datetime(start) data = list( app.db.balances.find( { "_id": { "$gte": dummy_id, } } ) ) resp = jsonResp({"data": data}, 200) return resp
def get_binbot_balance(self): """ More strict balance - No locked - Minus safety orders """ app = create_app() # Get a list of safety orders so_list = list(app.db.bots.aggregate( [ { "$addFields": { "so_num": {"$size": {"$objectToArray": "$safety_orders"}}, } }, {"$match": {"so_num": {"$ne": 0}}}, {"$addFields": {"s_os": {"$objectToArray": "$safety_orders"}}}, {"$unwind": "$safety_orders"}, {"$group": {"_id": {"so": "$s_os.v.so_size", "pair": "$pair"}}}, ] )) data = self.request_data()["balances"] df = pd.DataFrame(data) df["free"] = pd.to_numeric(df["free"]) df["asset"] = df["asset"].astype(str) df.drop("locked", axis=1, inplace=True) df.reset_index(drop=True, inplace=True) # Get table with > 0 balances = df[df["free"] > 0].to_dict("records") # Include safety orders for b in balances: for item in so_list: if b["asset"] in item["_id"]["pair"]: decimals = -(Decimal(self.price_filter_by_symbol(item["_id"]["pair"], "tickSize")).as_tuple().exponent) total_so = sum([float(x) if x != "" else 0 for x in item["_id"]["so"]]) b["free"] = round_numbers(float(b["free"]) - total_so, decimals) # filter out empty # Return response resp = jsonResp(balances, 200) return resp
def get_value(self): try: interval = request.view_args["interval"] except KeyError: interval = None filter = None # last 24 hours if interval == "1d": filter = { "updatedTime": { "$lt": datetime.now().timestamp(), "$gte": (datetime.now() - timedelta(days=1)).timestamp(), } } balance = list(app.db.balances.find(filter).sort([("_id", -1)])) if balance: resp = jsonResp({"data": balance}, 200) return resp
def delete_all_orders(self): """ Delete All orders by symbol - Optimal for open orders table """ symbol = request.args["symbol"] timestamp = int(round(tm.time() * 1000)) url = self.open_orders # query params -> args # path params -> view_args symbol = request.args["symbol"] params = [ ("symbol", symbol), ("timestamp", timestamp), ("recvWindow", self.recvWindow), ] headers = {"X-MBX-APIKEY": self.key} # Prepare request for signing r = requests.Request(url=url, params=params, headers=headers) prepped = r.prepare() query_string = urlparse(prepped.url).query total_params = query_string # Generate and append signature signature = hmac.new(self.secret.encode("utf-8"), total_params.encode("utf-8"), hashlib.sha256).hexdigest() params.append(("signature", signature)) # Response after request res = requests.delete(url=url, params=params, headers=headers) handle_error(res) data = res.json() if len(data) > 0: resp = jsonResp({"message": "Orders deleted", "data": data}, 200) else: resp = jsonResp_message("No open orders found!", 200) return resp
def get_diff(self): today = datetime.today() first = today.replace(day=1) lastMonth = first - timedelta(days=1) # One month from today first_lastMonth = today - timedelta(days=lastMonth.day) startTime = int(round(first_lastMonth.timestamp() * 1000)) pair = request.view_args["pair"] interval = request.view_args["interval"] params = { "symbol": pair, "interval": interval, "limit": lastMonth.day, "startTime": startTime, } url = self.candlestick_url res = requests.get(url=url, params=params) handle_error(res) data = res.json() df = pd.DataFrame(data) # New df with dates and close df_new = df[[0, 3]] df_new[3].astype(float) close_prices = df_new[3].astype( float).pct_change().iloc[1:].values.tolist() dates = df_new[0].iloc[1:].values.tolist() trace = { "x": dates, "y": close_prices, "type": "scatter", "mode": "lines+markers", } resp = jsonResp( { "message": "Successfully retrieved data", "data": trace }, 200) return resp
def handle_error(req): try: req.raise_for_status() if isinstance(json.loads(req.content), dict): # Binance code errors if "code" in json.loads(req.content).keys(): response = req.json() if response["code"] == -2010: return jsonResp({ "message": "Not enough funds", "error": 1 }, 200) # Uknown orders ignored, they are used as a trial an error endpoint to close orders (close deals) if response["code"] == -2011: return return jsonResp_message(json.loads(req.content), 200) except requests.exceptions.HTTPError as err: if err: print(req.json()) return jsonResp_message(req.json(), 200) else: return err except requests.exceptions.Timeout: # Maybe set up for a retry, or continue in a retry loop return jsonResp_message("handle_error: Timeout", 408) except requests.exceptions.TooManyRedirects: # Tell the user their URL was bad and try a different one return jsonResp_message("handle_error: Too many Redirects", 429) except requests.exceptions.RequestException as e: # catastrophic error. bail. return jsonResp_message(f"Catastrophic error: {e}", 500)