Beispiel #1
0
    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]
Beispiel #2
0
    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']],
        }
Beispiel #3
0
    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),
        }
Beispiel #4
0
    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']]
Beispiel #5
0
    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)]
Beispiel #6
0
    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)
Beispiel #7
0
    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)
Beispiel #8
0
    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
        ]
Beispiel #9
0
    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)
Beispiel #10
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
    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)
Beispiel #13
0
    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)
Beispiel #14
0
    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)
Beispiel #15
0
    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
Beispiel #16
0
    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]
Beispiel #17
0
 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)
Beispiel #18
0
    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
Beispiel #19
0
    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
Beispiel #20
0
 def get_last_price(self):
     try:
         return Decimal(stexchange_client.market_last(self.name))
     except StexchangeException as e:
         raise stexchange_http_exception_handler(e)