def peek(self, market: str, inner_resource: str): market = self.__fetch_market(market) if inner_resource == 'mydeals': return self._peek_me(market) elif inner_resource == 'marketdeals': try: response = stexchange_client.market_deals( market=market.name, limit=int(context.query_string['limit']), last_id=int(context.query_string['lastId'])) except StexchangeException as e: raise stexchange_http_exception_handler(e) return [{ 'id': deal['id'], 'time': format_iso_datetime( datetime.utcfromtimestamp(int(deal['time']))) if 'time' in deal else None, 'price': market.quote_currency.normalized_to_output(deal['price']), 'amount': market.base_currency.normalized_to_output(deal['amount']), 'type': deal['type'], } for deal in response]
def depth(self, market_name: str): limit = min(context.query_string.get('limit', 10), 10) interval = context.query_string.get('interval', 0) market = self.__fetch_market(market_name) try: depth = stexchange_client.order_depth(market.name, limit, interval) except StexchangeException as e: raise stexchange_http_exception_handler(e) return { 'asks': [{ 'price': market.quote_currency.normalized_to_output(ask[0]), 'amount': market.base_currency.normalized_to_output(ask[1]) } for ask in depth['asks']], 'bids': [{ 'price': market.quote_currency.normalized_to_output(bid[0]), 'amount': market.base_currency.normalized_to_output(bid[1]) } for bid in depth['bids']], }
def status(self, market_name: str): period = context.query_string.get('period') market = self.__fetch_market(market_name) try: if period == 'today': status = stexchange_client.market_status_today(market.name) else: status = stexchange_client.market_status( market.name, int(period)) except StexchangeException as e: raise stexchange_http_exception_handler(e) return { 'open': market.quote_currency.normalized_to_output(status['open']), 'high': market.quote_currency.normalized_to_output(status['high']), 'low': market.quote_currency.normalized_to_output(status['low']), 'close': market.quote_currency.normalized_to_output( status.get('close', None)), 'volume': market.base_currency.normalized_to_output(status['volume']), # FIXME: Is it (base_currency) right? 'deal': market.quote_currency.normalized_to_output( status['deal']), # FIXME: Is it (quote_currency) right? 'last': market.quote_currency.normalized_to_output(status['last']), 'period': status.get('period', None), }
def book(self, market_name: str): offset = context.query_string.get('offset', 0) limit = min(context.query_string.get('limit', 10), 10) side = 1 if (context.query_string['side'] == 'sell') else 2 market = self.__fetch_market(market_name) try: result = stexchange_client.order_book(market.name, side, offset, limit) except StexchangeException as e: raise stexchange_http_exception_handler(e) return [{ 'createdAt': format_iso_datetime(datetime.utcfromtimestamp(int(order['ctime']))) if 'ctime' in order else None, 'modifiedAt': format_iso_datetime(datetime.utcfromtimestamp(int(order['mtime']))) if 'mtime' in order else None, 'market': order.get('market', None), 'type': 'limit' if order.get('type', None) == 1 else 'market', 'side': 'sell' if order.get('side', None) == 1 else 'buy', 'amount': market.base_currency.normalized_to_output(order.get( 'amount', None)), 'price': market.quote_currency.normalized_to_output(order.get( 'price', None)), } for order in result['orders']]
def list(self): try: response = stexchange_client.market_list() supporting_markets = Market.query.all() except StexchangeException as e: raise stexchange_http_exception_handler(e) return [{ 'name': market['name'], 'stock': market['stock'], 'stockPrec': market['stock_prec'], 'money': market['money'], 'feePrec': market['fee_prec'], 'minAmount': list(filter( lambda y: y.name == market['name'], supporting_markets))[0].base_currency.normalized_to_output( market['min_amount']), 'moneyPrec': market['money_prec'], } for market in response if any(market['name'] == sm.name for sm in supporting_markets)]
def overview(self): try: response = [] asset_summaries = stexchange_client.asset_summary() for asset in asset_summaries: currency = Currency.query.filter(Currency.symbol == asset['name']).one_or_none() if currency is None: continue response.append( { 'name': asset['name'], 'currency': currency.to_dict(), 'totalBalance': currency.normalized_to_output(asset['total_balance']), 'availableCount': currency.normalized_to_output(asset['available_count']), 'availableBalance': currency.normalized_to_output(asset['available_balance']), 'freezeCount': currency.normalized_to_output(asset['available_count']), 'freezeBalance': currency.normalized_to_output(asset['available_count']), } ) return response except StexchangeException as e: raise stexchange_http_exception_handler(e)
def history(self): currency = Currency.query.filter(Currency.symbol == context.query_string.get('asset', None)).one_or_none() if currency is None: raise HttpBadRequest('Currency not found', 'market-not-found') try: return [ { 'time': format_iso_datetime( datetime.utcfromtimestamp(int(x['timestamp']))) if 'timestamp' in x else None, 'asset': x['asset'], 'currency': currency.to_dict(), 'business': x['business'], 'change': currency.normalized_to_output(x['change']), 'balance': currency.normalized_to_output(x['balance']), 'detail': x['detail'], } for x in stexchange_client.balance_history( context.identity.id, asset=context.query_string.get('asset', None), limit=context.query_string.get('take', self.PAGE_SIZE), business='deposit,withdraw,cashin,cashout,cashback', offset=context.query_string.get('skip', self.PAGE_SIZE * context.query_string.get('page', 0)) )['records'] ] except StexchangeException as e: raise stexchange_http_exception_handler(e)
def kline(self, market_name: str): interval = context.query_string.get('interval') start = context.query_string.get('start') end = context.query_string.get('end') market = self.__fetch_market(market_name) try: kline = stexchange_client.market_kline(market.name, start, end, interval) except StexchangeException as e: raise stexchange_http_exception_handler(e) return [ { 'market': market.name, 'time': k[0], 'o': market.quote_currency.normalized_to_output(k[1]), 'h': market.quote_currency.normalized_to_output(k[3]), 'l': market.quote_currency.normalized_to_output(k[4]), 'c': market.quote_currency.normalized_to_output(k[2]), 'volume': market.base_currency.normalized_to_output( k[5]), # FIXME: Is it (base_currency) right? 'amount': market.base_currency.normalized_to_output( k[6]), # FIXME: Is it (base_currency) right? } for k in kline ]
def create(self): client_id = context.identity.id market = Market.query.filter( Market.name == context.form['marketName']).one_or_none() if market is None: raise HttpBadRequest('Market not found', 'market-not-found') side = 1 if (context.form['side'] == 'sell') else 2 amount = market.base_currency.input_to_normalized( context.form['amount']) price = market.quote_currency.input_to_normalized( context.form.get('price', None)) market.validate_ranges(type_=context.form['side'], total_amount=amount, price=price) try: if context.form['type'] == 'market': if price is not None: raise HttpBadRequest( 'Price should not be sent in market orders', 'bad-price') order = stexchange_client.order_put_market( user_id=client_id, market=market.name, side=side, amount=Currency.format_normalized_string(amount), taker_fee_rate=market.taker_commission_rate, source="nothing", # FIXME ) elif context.form['type'] == 'limit': if price is None: raise HttpBadRequest( 'Price should be sent in market orders', 'bad-price') order = stexchange_client.order_put_limit( user_id=client_id, market=market.name, side=side, amount=Currency.format_normalized_string(amount), price=Currency.format_normalized_string(price), taker_fee_rate=market.taker_commission_rate, maker_fee_rate=market.maker_commission_rate, source="nothing", # FIXME ) else: raise HttpNotFound('Bad status.') return order_to_dict(market, order) except StexchangeException as e: raise stexchange_http_exception_handler(e)
def list(self): supporting_assets = Currency.query.all() try: return [{ 'name': x['name'], 'currency': list(filter(lambda y: y.symbol == x['name'], supporting_assets))[0].to_dict(), 'prec': x['prec'], } for x in stexchange_client.asset_list() if any(x['name'] == sm.symbol for sm in supporting_assets)] except StexchangeException as e: raise stexchange_http_exception_handler(e)
def last(self, market_name: str): market = self.__fetch_market(market_name) try: return { 'name': market.name, 'price': market.quote_currency.normalized_to_output( stexchange_client.market_last(market.name)), } except StexchangeException as e: raise stexchange_http_exception_handler(e)
def get(self, order_id: int = None): client_id = context.identity.id if context.identity.is_in_roles('client') \ else context.query_string['clientId'] try: if order_id is None: offset = context.query_string.get('offset', 0) limit = min(context.query_string.get('limit', 10), 10) if context.query_string['status'] == 'pending': orders = stexchange_client.order_pending( user_id=client_id, market=context.query_string['marketName'], offset=offset, limit=limit, ) elif context.query_string['status'] == 'finished': orders = stexchange_client.order_finished( user_id=client_id, market=context.query_string['marketName'], offset=offset, limit=limit, side=0, start_time=0, end_time=0, ) else: raise HttpNotFound('Bad status.') return [ order_to_dict(self.__fetch_market(), order) for order in orders['records'] ] else: if context.query_string['status'] == 'pending': order = stexchange_client.order_pending_detail( market=context.query_string['marketName'], order_id=int(order_id), ) elif context.query_string['status'] == 'finished': order = stexchange_client.order_finished_detail( order_id=int(order_id), ) else: raise HttpNotFound('Bad status.') return order_to_dict(self.__fetch_market(), order) except StexchangeException as e: raise stexchange_http_exception_handler(e)
def cancel(self, order_id: int): client_id = context.identity.id if context.identity.is_in_roles('client') \ else context.query_string['clientId'] try: order = stexchange_client.order_cancel( user_id=client_id, market=context.query_string['marketName'], order_id=int(order_id), ) return order_to_dict(self.__fetch_market(), order) except StexchangeException as e: raise stexchange_http_exception_handler(e)
def deal(self, order_id: int): client_id = context.identity.id if context.identity.is_in_roles('client') \ else context.query_string['clientId'] offset = context.query_string.get('offset', 0) limit = min(context.query_string.get('limit', 100), 100) try: deals = stexchange_client.order_deals(order_id=int(order_id), offset=offset, limit=limit) market = self.__fetch_market() return [ { 'id': deal['id'], 'time': format_iso_datetime( datetime.utcfromtimestamp(int(deal['time']))) if 'time' in deal else None, 'user': deal['user'], 'role': 'maker' if deal['role'] == 1 else 'taker', 'amount': market.base_currency.normalized_to_output(deal['amount']), 'price': market.quote_currency.normalized_to_output(deal['price']), 'deal': market.quote_currency.normalized_to_output( deal['deal']), # FIXME: Is it (quote_currency) 'fee': market.quote_currency.normalized_to_output( deal['fee']), # FIXME: Is it (quote_currency) 'orderId': deal['deal_order_id'], } for deal in deals['records'] if (context.identity.is_in_roles('admin') or ( deal['user'] == client_id)) ] except StexchangeException as e: raise stexchange_http_exception_handler(e)
def overview(self): supporting_assets = Currency.query.all() asset_names = [x['name'] for x in stexchange_client.asset_list()] result = [] try: for key, value in stexchange_client.balance_query(context.identity.id, *asset_names).items(): if any(key == sm.symbol for sm in supporting_assets): currency = list(filter(lambda x: x.symbol == key, supporting_assets))[0] result.append({ 'name': key, 'currency': currency.to_dict(), 'available': currency.normalized_to_output(value['available']), 'freeze': currency.normalized_to_output(value['freeze']), }) except StexchangeException as e: raise stexchange_http_exception_handler(e) return result
def summary(self, market_name: str): market = self.__fetch_market(market_name) try: response = stexchange_client.market_summary(market_name) except StexchangeException as e: raise stexchange_http_exception_handler(e) return [{ 'name': market_summary['name'], 'bidAmount': market.base_currency.normalized_to_output( market_summary['bid_amount']), 'bidCount': market_summary['bid_count'], 'askAmount': market.base_currency.normalized_to_output( market_summary['ask_amount']), 'askCount': market_summary['ask_count'], } for market_summary in response]
def _peek_me(self, market: Market): try: response = stexchange_client.market_user_deals( user_id=context.identity.id, market=market.name, offset=int(context.query_string['offset']), limit=int(context.query_string['limit'])) return [ { 'id': deal['id'], 'time': format_iso_datetime( datetime.utcfromtimestamp(int(deal['time']))) if 'time' in deal else None, 'side': deal['side'], 'user': deal['user'], 'price': market.quote_currency.normalized_to_output(deal['price']), 'amount': market.base_currency.normalized_to_output(deal['amount']), 'fee': market.quote_currency.normalized_to_output( deal['fee']), # FIXME: Is it (quote_currency) 'deal': market.quote_currency.normalized_to_output( deal['deal']), # FIXME: Is it (quote_currency) 'dealOrderId': deal['deal_order_id'], 'role': deal['role'], } for deal in response['records'] ] except StexchangeException as e: raise stexchange_http_exception_handler(e)
def reject(self, shaparak_out_id: int): error = context.form.get('error') shaparak_out = Cashout.query.filter( Cashout.id == shaparak_out_id).one_or_none() if shaparak_out is None: raise HttpNotFound() if shaparak_out.reference_id is not None: raise HttpBadRequest('This transaction already accepted.') if shaparak_out.error is not None: raise HttpBadRequest('This transaction already has an error.') payment_gateway = shaparak_out.payment_gateway shaparak_out.error = error try: # Cash back (without commission) FIXME: Really without commission? stexchange_client.balance_update( user_id=shaparak_out.member_id, asset=shaparak_out.payment_gateway.fiat_symbol, # FIXME business='cashback', # FIXME business_id=shaparak_out.id, change=payment_gateway.fiat.format_normalized_string( shaparak_out.amount), detail=shaparak_out.to_dict(), ) # FIXME: Important !!!! : rollback the updated balance if # DBSession.commit() was not successful except StexchangeException as e: raise stexchange_http_exception_handler(e) return shaparak_out
def schedule(self): amount = context.form.get('amount') sheba_address_address_id = context.form.get('shebaAddressId') # Check cashout range payment_gateway = PaymentGateway.query.filter( PaymentGateway.name == context.form.get( 'paymentGatewayName')).one() amount = payment_gateway.fiat.input_to_normalized(amount) # TODO: More strict check and review how we control payment gateways if (payment_gateway is None) or (payment_gateway.fiat_symbol not in ['IRR', 'TIRR']): raise HttpBadRequest('Bad payment gateway') Fiat.query.filter(Fiat.symbol == payment_gateway.fiat_symbol).one() if (payment_gateway.cashout_max != Decimal(0) and amount > payment_gateway.cashout_max) or \ amount < payment_gateway.cashout_min: raise HttpBadRequest('Amount is not between valid cashout range.') commission = payment_gateway.calculate_cashout_commission(amount) # Check balance try: available_balance = Decimal( stexchange_client.balance_query(context.identity.id, payment_gateway.fiat_symbol) [payment_gateway.fiat_symbol]['available']) except StexchangeException as e: raise stexchange_http_exception_handler(e) # FIXME: Think about concurrency if available_balance < amount + commission: raise HttpBadRequest('Not enough balance') # Check sheba target_sheba = BankAccount.query \ .filter(BankAccount.id == sheba_address_address_id) \ .filter(BankAccount.client_id == context.identity.id) \ .one_or_none() if target_sheba is None: raise HttpBadRequest('Sheba address not found.') if target_sheba.is_verified is False: raise HttpConflict('Sheba address is not verified.') shaparak_out = Cashout() shaparak_out.fiat_symbol = payment_gateway.fiat_symbol shaparak_out.member_id = context.identity.id shaparak_out.amount = amount shaparak_out.commission = commission shaparak_out.banking_id_id = sheba_address_address_id shaparak_out.payment_gateway_name = payment_gateway.name # FIXME DBSession.add(shaparak_out) # Set new balance try: stexchange_client.balance_update( user_id=shaparak_out.member_id, asset=payment_gateway.fiat_symbol, # FIXME business='cashout', # FIXME business_id=shaparak_out.id, change= f'-{payment_gateway.fiat.format_normalized_string(amount + commission)}', # FIXME Prevent negative amounts detail=shaparak_out.to_dict(), ) # FIXME: Important !!!! : rollback the updated balance if # DBSession.commit() was not successful except StexchangeException as e: raise stexchange_http_exception_handler(e) return shaparak_out
def get_last_price(self): try: return Decimal(stexchange_client.market_last(self.name)) except StexchangeException as e: raise stexchange_http_exception_handler(e)