# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
# default_exp __init__

# +
# hide
import os
notebooks_dir = os.getcwd()
project_dir = os.path.dirname(notebooks_dir)

import sys
sys.path.append(project_dir)
# -

# # MXC

from ccstabilizer import Exchange
from ccstabilizer import secrets

# +
# export
from decimal import Decimal


class MXC(Exchange):

    def __init__(self):
        super().__init__()
        self.mxc = MXCAPI(os.environ['MXC_ACCESS_KEY'], os.environ['MXC_SECRET_KEY'])
        self.update_trading_specifications()

    def update_trading_specification(self, crypto_symbol, fiat_symbol):
        return self.update_trading_specifications().get((crypto_symbol, fiat_symbol), {})

    def update_trading_specifications(self):
        for symbol_info in self.mxc.get_symbols():
            crypto_symbol, fiat_symbol = symbol_info.get('symbol', '').split('_')
            trading_spec = {}
            if 'quantity_scale' in symbol_info:
                trading_spec['min_trade_unit'] = Decimal('0.1') ** symbol_info.get('quantity_scale', 0)
            if 'min_amount' in symbol_info:
                trading_spec['min_trade_fiat_money_limit'] = Decimal(symbol_info.get('min_amount', '0'))
            if 'maker_fee_rate' in symbol_info:
                trading_spec['fee_rate'] = Decimal(symbol_info.get('maker_fee_rate', '0'))
            if 'limited' in symbol_info:
                trading_spec['liquid'] = symbol_info.get('limited', False)
            self.trading_specifications[(crypto_symbol, fiat_symbol)] = trading_spec
        self.get_trading_specification('XPX', 'USDT')['min_trade_fiat_money_limit'] *= 4
        return self.trading_specifications

    def get_portfolio(self):
        return {
            symbol: Decimal(asset.get('available', '0')) for symbol, asset in self.mxc.get_account_info().items()
        }

    def get_price(self, crypto_symbol, fiat_symbol):
        now_ticker = self.mxc.get_ticker(f'{crypto_symbol}_{fiat_symbol}')[0]
        now_buy_fiat_price_without_fee = Decimal(now_ticker.get('ask', 'Infinity'))
        now_sell_fiat_price_without_fee = Decimal(now_ticker.get('bid', '0'))
        fee_rate = self.get_trading_specification(crypto_symbol, fiat_symbol).get('fee_rate', 0)
        return {
            'now_buy_fiat_price': self.get_buy_fiat_price(now_buy_fiat_price_without_fee, fee_rate),
            'now_sell_fiat_price': self.get_sell_fiat_price(now_sell_fiat_price_without_fee, fee_rate),
            'now_buy_fiat_price_without_fee': now_buy_fiat_price_without_fee,
            'now_sell_fiat_price_without_fee': now_sell_fiat_price_without_fee,
        }

    def get_buy_fiat_price(self, fiat_price_without_fee, fee_rate):
        return fiat_price_without_fee * (1 + fee_rate)

    def get_sell_fiat_price(self, fiat_price_without_fee, fee_rate):
        return fiat_price_without_fee * (1 - fee_rate)

    def buy(self, crypto_symbol, fiat_symbol, amount, fiat_price_without_fee):
        if amount <= 0:
            raise Exception('MXC::buy  amount <= 0')
        self.mxc.place_order(f'{crypto_symbol}_{fiat_symbol}', str(fiat_price_without_fee), str(amount), 'BID', 'IMMEDIATE_OR_CANCEL')

    def sell(self, crypto_symbol, fiat_symbol, amount, fiat_price_without_fee):
        if amount <= 0:
            raise Exception('MXC::sell  amount <= 0')
        self.mxc.place_order(f'{crypto_symbol}_{fiat_symbol}', str(fiat_price_without_fee), str(amount), 'ASK', 'IMMEDIATE_OR_CANCEL')

    def has_enough_unused_fiat_money(self, buy_fiat_money, unused_fiat_money):
        return buy_fiat_money <= unused_fiat_money

    def trade_fiat_money_is_larger_than_limit(self, crypto_symbol, fiat_symbol, amount, fiat_price_without_fee):
        # Just for MXC
        return fiat_price_without_fee * amount > self.get_trading_specification(crypto_symbol, fiat_symbol).get('min_trade_fiat_money_limit', 0)


# -

# ## MXC API
# https://mxcdevelop.github.io/APIDoc/

# +
# export
import contextlib
import hashlib
import hmac
import os
import requests
import time

from urllib import parse


class MXCAPI(object):

    ROOT_URL = 'https://www.mxc.ceo'
    ERROR_MESSAGES = {
        400: '请求参数无效。',
        401: '签名验证失败。',
        429: '请求过于频繁。',
        10072: '无效的 Access Key。',
        10073: '无效的请求时间。',
        30000: '当前交易对已暂停交易。',
        30001: '当前交易方向不允许下单。',
        30002: '小于最小交易金额。',
        30003: '大于最大交易金额。',
        30004: '持仓不足。',
        30005: '卖出超额。',
        30010: '下单价格超过范围。',
        30016: '暂停交易。',
        30019: '订单集合超出最大允许长度。',
        30020: '受限制的交易对，暂不支持 API 访问。',
        30021: '无效的交易对。',
    }

    def __init__(self, API_KEY, SECRET_KEY):
        self.API_KEY = API_KEY
        self.SECRET_KEY = SECRET_KEY

    @staticmethod
    def _get_server_time():
        return int(time.time())

    def _sign(self, method, path, original_params=None):
        params = {
            'api_key': self.API_KEY,
            'req_time': type(self)._get_server_time(),
        }
        if original_params is not None:
            params.update(original_params)
        params_str = '&'.join('{}={}'.format(k, params[k]) for k in sorted(params))
        to_sign = '\n'.join([method, path, params_str])
        params.update({
            'sign': hmac.new(self.SECRET_KEY.encode(), to_sign.encode(), hashlib.sha256).hexdigest()
        })
        return params

    def _request(self, method, path, params):
        url = '{}{}'.format(type(self).ROOT_URL, path)
        with contextlib.closing(
            requests.request(method, url, params=params)
        ) as response:
            response_json = response.json()
            code = response_json.get('code', 0)
            if code != 200:
                raise Exception(
                    f'{type(self).ERROR_MESSAGES.get(code, response_json.get("msg", "未知错误。"))}\n'
                    f'path={path}\n'
                    f'params={params}\n'
                )
            return response_json.get('data', {})

    def get_symbols(self):
        """marget data"""
        method = 'GET'
        path = '/open/api/v2/market/symbols'
        params = {'api_key': self.API_KEY}
        return self._request(method, path, params)

    def get_rate_limit(self):
        """rate limit"""
        method = 'GET'
        path = '/open/api/v2/common/rate_limit'
        params = {'api_key': self.API_KEY}
        return self._request(method, path, params)

    def get_timestamp(self):
        """get current time"""
        method = 'GET'
        path = '/open/api/v2/common/timestamp'
        params = {'api_key': self.API_KEY}
        return self._request(method, path, params)

    def get_ticker(self, symbol):
        """get ticker information"""
        method = 'GET'
        path = '/open/api/v2/market/ticker'
        params = {
            'api_key': self.API_KEY,
            'symbol': symbol,
        }
        return self._request(method, path, params)

    def get_depth(self, symbol, depth):
        """get market depth"""
        method = 'GET'
        path = '/open/api/v2/market/depth'
        params = {
            'api_key': self.API_KEY,
            'symbol': symbol,
            'depth': depth,
        }
        return self._request(method, path, params)

    def get_deals(self, symbol, limit):
        """get deals records"""
        method = 'GET'
        path = '/open/api/v2/market/deals'
        params = {
            'api_key': self.API_KEY,
            'symbol': symbol,
            'limit': limit,
        }
        return self._request(method, path, params)

    def get_kline(self, symbol, interval):
        """k-line data"""
        method = 'GET'
        path = '/open/api/v2/market/kline'
        params = {
            'api_key': self.API_KEY,
            'symbol': symbol,
            'interval': interval,
        }
        return self._request(method, path, params)

    def get_account_info(self):
        """account information"""
        method = 'GET'
        path = '/open/api/v2/account/info'
        params = self._sign(method, path)
        return self._request(method, path, params)

    def _request_with_json(self, method, path, params, json):
        url = '{}{}'.format(type(self).ROOT_URL, path)
        with contextlib.closing(
            requests.request(method, url, params=params, json=json)
        ) as response:
            response_json = response.json()
            code = response_json.get('code', 0)
            if code != 200:
                raise Exception(
                    type(self).ERROR_MESSAGES.get(code, response_json.get('msg', '未知错误。'))
                )
            return response_json.get('data', {})

    def place_order(self, symbol, price, quantity, trade_type, order_type):
        """place order"""
        method = 'POST'
        path = '/open/api/v2/order/place'
        params = self._sign(method, path)
        data = {
            'symbol': symbol,
            'price': price,
            'quantity': quantity,
            'trade_type': trade_type,
            'order_type': order_type,
        }
        return self._request_with_json(method, path, params, data)

    def batch_orders(self, orders):
        """batch order"""
        method = 'POST'
        path = '/open/api/v2/order/place_batch'
        params = self._sign(method, path)
        return self._request_with_json(method, path, params, orders)

    def cancel_order(self, order_id):
        """cancel in batch"""
        method = 'DELETE'
        path = '/open/api/v2/order/cancel'

        origin_trade_no = order_id
        if isinstance(order_id, list):
            origin_trade_no = parse.quote(','.join(order_id))
        params = self._sign(method, path, original_params={'order_ids': origin_trade_no})
        if isinstance(order_id, list):
            params['order_ids'] = ','.join(order_id)

        return self._request(method, path, params)

    def get_open_orders(self, symbol):
        """current orders"""
        method = 'GET'
        path = '/open/api/v2/order/open_orders'

        original_params = {
            'symbol': symbol,
        }
        params = self._sign(method, path, original_params=original_params)

        return self._request(method, path, params)

    def get_all_orders(self, symbol, trade_type):
        """order list"""
        method = 'GET'
        path = '/open/api/v2/order/list'

        original_params = {
            'symbol': symbol,
            'trade_type': trade_type,
        }
        params = self._sign(method, path, original_params=original_params)

        return self._request(method, path, params)

    def query_order(self, order_id):
        """query order"""
        method = 'GET'
        path = '/open/api/v2/order/query'

        origin_trade_no = order_id
        if isinstance(order_id, list):
            origin_trade_no = parse.quote(','.join(order_id))
        original_params = {
            'order_ids': origin_trade_no,
        }
        params = self._sign(method, path, original_params=original_params)
        if isinstance(order_id, list):
            params['order_ids'] = ','.join(order_id)

        return self._request(method, path, params)

    def get_deal_orders(self, symbol):
        """account deal records"""
        method = 'GET'
        path = '/open/api/v2/order/deals'

        original_params = {
            'symbol': symbol,
        }
        params = self._sign(method, path, original_params=original_params)

        return self._request(method, path, params)

    def get_deal_detail(self, order_id):
        """deal detail"""
        method = 'GET'
        path = '/open/api/v2/order/deal_detail'

        original_params = {
            'order_id': order_id,
        }
        params = self._sign(method, path, original_params=original_params)

        return self._request(method, path, params)


# -

MXCAPI(os.environ['MXC_ACCESS_KEY'], os.environ['MXC_SECRET_KEY']).get_deal_orders('ZYRO_USDT')

exchange = MXC()

exchange.get_trading_specification('AR', 'USDT')

fiat_price = exchange.get_price('VIDY', 'USDT')['now_buy_fiat_price_without_fee']

exchange.buy('VIDY', 'USDT', 7 / fiat_price, fiat_price)

StarcoderdataJupyterScriptsDedupFiltered