def exchange_buy(self, market, symbol: CurrencySymbol, amount, price): if market.name == const.BITFINEX: json = self.finex.place_order(amount=amount, price=price, side='buy', symbol=symbol.value + 'usd') return json['id'] elif market.name == const.BITHUMB: json = self.thumb.new_buy_order(symbol=symbol, amount=amount) print(json) raise HanpunError('not impl')
def order_status(self, market, order_id): if market.name == const.BITFINEX: json = self.finex.order_status(order_id=order_id) if float(json['remaining_amount']) < 0.01: return OrderStatus.SUCCESS elif bool(json['is_cancelled']): return OrderStatus.IS_CANCELLED else: return OrderStatus.IN_PROGRESS elif market.name == const.BITHUMB: pass raise HanpunError('not impl')
def check_market_price(tickers): assert len(tickers) > 60, f'ticker count {len(tickers)}' last_price = tickers[0].last_price ALLOWED_ERROR_RANGE_PER = 5 for t in tickers: pass error_range = abs(last_price - t.last_price) error_range_perc = error_range / last_price * 100 if error_range_perc >= ALLOWED_ERROR_RANGE_PER: raise HanpunError(f'error_range {error_range}') return tickers[0]
def withdraw(self, symbol: CurrencySymbol, amount, from_market, to_market): assert all([symbol, from_market, to_market]) assert amount > 0 to_balance = to_market.balances.filter( ExchangeMarketBalance.symbol == symbol).first() assert to_balance, '계좌가 없습니다.' if from_market.name == const.BITFINEX: json = self.finex.withdraw(symbol=symbol, amount=amount, address=to_balance.address, payment_id=to_balance.destination) return json raise HanpunError('not impl')
def exchange_sell(self, market, symbol: CurrencySymbol, amount, price): """ :param market: :param symbol: :param amount: :param price: :return: order_id """ if market.name == const.BITFINEX: json = self.finex.place_order(amount=amount, price=price, side='sell', symbol=symbol.value + 'usd') return json elif market.name == const.BITHUMB: json = self.thumb.new_sell_order(symbol=symbol, amount=amount) return json raise HanpunError('not impl')
def place_order(self, amount, price, side, symbol, ord_type='exchange limit', exchange='bitfinex'): """ Submit a new order. :param amount: :param price: :param side: either 'buy' or 'sell' :param ord_type: exchange limit :param symbol: :param exchange: :return: """ payload = { "request": "/v1/order/new", "nonce": self._nonce, "symbol": symbol, "amount": str(Decimal(amount)), "price": str(Decimal(price)), "exchange": exchange, "side": side, "type": ord_type } signed_payload = self._sign_payload(payload) r = requests.post(self.URL + "/order/new", headers=signed_payload, verify=True, timeout=10) json_resp = r.json() try: json_resp['order_id'] except: raise HanpunError(json_resp.get('message', 'Unknown error')) return json_resp
def cancel_all_orders(self, market): print(f'cancel_all_orders market {market.name}') if market.name == const.BITFINEX: json = self.finex.cancel_all_orders() return json raise HanpunError('not impl')
def calc(): mc = MarketController(db_session=db_session) markets = mc.all_markets() tc = TradeController(db_session=db_session) since = datetime.datetime.now() - datetime.timedelta(minutes=180) ticker_bucket = [] for market in markets: tickers = (db_session.query(Ticker).filter( Ticker.exchange_market_id == market.id, Ticker.created_at >= since).order_by( Ticker.created_at.desc()).all()) # tickers 가 60개 이상이 되야지 믿을수 있지. if len(tickers) > 60: ticker_bucket.append(tickers) # 거래소 믿을수 있는 시장가 구하기 market_last_tickers = [] for tickers in ticker_bucket: try: market_last_tickers.append(check_market_price(tickers)) except HanpunError as e: print(e) print( f'markets {[ticker.exchange_market.name for ticker in market_last_tickers]}' ) assert len(market_last_tickers) > 0, '현재 가치있는 거래소가 없음.' # 수익성 가장 좋은 market 찾기 ask = 판매가, bid = 구매가 low_ask_ticker = None high_bid_ticker = None for ticker in market_last_tickers: low_ask_ticker = ticker if low_ask_ticker is None or ticker.ask < low_ask_ticker.ask else low_ask_ticker high_bid_ticker = ticker if high_bid_ticker is None or ticker.bid > high_bid_ticker.bid else high_bid_ticker balance_amount = tc.balance(low_ask_ticker.exchange_market, CurrencySymbol.USD) assert balance_amount > 0, 'balances에 돈이 없다 ㅠ' cost_of_buy = round(low_ask_ticker.ask * 1000000) / 1000000 buyable_amount = balance_amount / cost_of_buy - 0.1 print( f'---------------------------------------------------------------------------' ) print( f'low_ticker {low_ask_ticker.ask} {low_ask_ticker.exchange_market.name}' ) print( f'high_ticker {high_bid_ticker.bid} {high_bid_ticker.exchange_market.name}' ) profit_per_unit = high_bid_ticker.bid - low_ask_ticker.ask print( f'profit_per_unit {profit_per_unit} {profit_per_unit / cost_of_buy * 100}% ' ) print( f'buy_available_amount {buyable_amount} balance_amount {balance_amount} ' ) print( f'---------------------------------------------------------------------------' ) fee_sum = 0 for ticker in [low_ask_ticker, high_bid_ticker]: trade_ob = ticker.exchange_market.trade_fees.filter( TradeFee.symbol == ticker.symbol).first() trade_fee = buyable_amount * cost_of_buy * (trade_ob.fee_percent / 100) withdrawal_ob = ticker.exchange_market.withdrawal_fees.filter( WithdrawalFee.symbol == ticker.symbol).first() withdrawal_fee = cost_of_buy * withdrawal_ob.fee print(f'ticker {ticker.exchange_market.name} trade_fee {trade_fee}') print( f'ticker {ticker.exchange_market.name} withdrawal_fee {withdrawal_fee}' ) fee_sum += trade_fee + withdrawal_fee print(f'total fee : ${fee_sum}') estimated_profit_price = (profit_per_unit * buyable_amount) - fee_sum used_money = cost_of_buy * buyable_amount print( f'estimated profit amount : ${estimated_profit_price} used_money : ${used_money}' ) print(f'profit_per {estimated_profit_price / used_money}%') assert estimated_profit_price > 0, '이득이 마이너스는 아니여야잖아' try: # 어마운트를 1로 조정 exchange_market = low_ask_ticker.exchange_market order_id = tc.exchange_buy(exchange_market, symbol=low_ask_ticker.symbol, amount=buyable_amount, price=cost_of_buy) for idx in range(30): order_status = tc.order_status(exchange_market, order_id) print(f'order_status {order_status}') if order_status == OrderStatus.SUCCESS: balance_amount = tc.balance(low_ask_ticker.exchange_market, symbol=low_ask_ticker.symbol) withdraw(symbol=low_ask_ticker.symbol, amount=balance_amount, to_market=high_bid_ticker.exchange_market, from_market=low_ask_ticker.exchange_market) check_deposit(low_ask_ticker.symbol, high_bid_ticker.exchange_market) break if order_status == OrderStatus.IS_CANCELLED: raise HanpunError('OrderStatus.IS_CANCELLED') time.sleep(1) tc.cancel_all_orders(exchange_market) raise HanpunError('timeout error') except Exception as e: print(e) raise e