예제 #1
0
    def test_dynamically_change_order_with_tx_import(self, name, test_data,
                                                     get_txs_scrypt,
                                                     get_txs_eth,
                                                     get_slippage):
        get_slippage.return_value = Decimal('0')
        pair_name = test_data['pair_name']
        times = test_data['times']
        self._create_order(pair_name=pair_name, amount_base=None,
                           amount_quote=11.11)
        amount_base = self.order.amount_base
        card = self.order.deposit_address.reserve
        amount_quote = self.order.amount_quote
        mock_amount = money_format(amount_quote * times, places=8)
        minutes_after_expire = test_data['minutes_after_expire']
        skip_minutes = settings.PAYMENT_WINDOW + minutes_after_expire
        now = self.order.created_on + timedelta(minutes=skip_minutes)
        with freeze_time(now):
            if minutes_after_expire >= 0:
                self.assertTrue(self.order.expired, name)

            get_txs_eth.return_value = self.get_ethash_tx(mock_amount,
                                                          card.address)
            get_txs_scrypt.return_value = self.get_scrypt_tx(mock_amount,
                                                             card.address)
            self.import_txs_task.apply()
            txs = self.order.transactions.all()
            self.assertEqual(len(txs), 1, name)
            tx = txs.last()
            self.assertAlmostEqual(tx.amount, mock_amount, 7, name)
            self.order.refresh_from_db()
            self.assertEqual(self.order.status, Order.PAID_UNCONFIRMED)
            self.assertAlmostEqual(
                self.order.amount_quote, mock_amount, 7, name)
            expected_base = money_format(
                (amount_base + self.order.withdrawal_fee) *
                times - self.order.withdrawal_fee,
                places=8
            )
            self.assertAlmostEqual(
                self.order.amount_base, expected_base, 7, name)
            self.assertFalse(self.order.expired, name)
            if minutes_after_expire < 0:
                self.assertEqual(
                    self.order.payment_window, settings.PAYMENT_WINDOW, name)
            else:
                self.assertEqual(
                    self.order.payment_window,
                    settings.PAYMENT_WINDOW * 2 + minutes_after_expire,
                    name)
예제 #2
0
 def refund_payment(self, payment):
     if not payment.is_success:
         return False
     order = payment.order
     if not order:
         return False
     if order.status != order.PAID_UNCONFIRMED:
         return False
     params = {
         'currency': payment.currency.code,
         'amount': str(money_format(payment.amount_cash, places=2)),
         'clientRequestId': 'refund_{}'.format(order.unique_reference),
         'clientUniqueId': 'refund_{}'.format(order.unique_reference),
         'relatedTransactionId': payment.secondary_payment_system_id,
         'authCode': payment.auth_code
     }
     res = self.api.refundTransaction(**params)
     status = res.get('transactionStatus', '')
     if status != 'APPROVED':
         return False
     order.cancel()
     payment.is_success = False
     payment.save()
     payment.flag(val=res)
     return True
예제 #3
0
 def _prepare_request_data(self, order, payment, **kwargs):
     kwargs['merchantDetails'] = kwargs.get('merchantDetails', {})
     kwargs['merchantDetails'].update(
         {'customField1': order.unique_reference})
     amount = money_format(order.amount_quote, places=2)
     kwargs.update({
         'amount': str(amount),
         'currency': order.pair.quote.code,
         'isDynamic3D': '1',
         'dynamic3DMode': 'ON',
     })
     if order.status == order.PAID_UNCONFIRMED:
         pref = payment.payment_preference
         ccexp = pref.ccexp.split('/')
         kwargs.update({
             'cardData': {
                 'cardNumber': pref.identifier,
                 'cardHolderName': pref.secondary_identifier,
                 'expirationMonth': ccexp[0],
                 'expirationYear': ccexp[1],
                 'CVV': pref.cvv
             },
             'orderId': payment.payment_system_id,
             'transactionType': 'Auth'
         })
     return kwargs
예제 #4
0
 def strip_payload_decimal(self, data, key):
     _raw = data.get(key, None)
     if _raw:
         try:
             _value = Decimal(str(_raw))
             _formatted = money_format(_value, places=8)
             data[key] = _formatted
         except Exception:
             pass
     return data
예제 #5
0
    def test_do_not_release_if_same_tx_available_xvg(self,
                                                     release_coins,
                                                     scrypt_health,
                                                     list_txs):
        # XVG has 6 decimal points rounding on most wallets so need
        # to make sure
        actual_rounding = 6
        legacy_rounding = 8
        xvg = Currency.objects.get(code='XVG')

        xvg.rounding = legacy_rounding
        xvg.save()
        scrypt_health.return_value = {}
        scrypt = ScryptRpcApiClient()
        amount = Decimal('100.12345678')
        order_legacy = self._create_paid_order(
            pair_name='XVGBTC', amount_base=amount
        )

        xvg.rounding = actual_rounding
        xvg.save()
        self.assertEqual(order_legacy.amount_base, amount)
        xvg.rounding = actual_rounding
        xvg.save()
        amount_on_blockchain = money_format(amount, places=actual_rounding)
        order = self._create_paid_order(pair_name='XVGBTC', amount_base=amount)
        self.assertEqual(order.amount_base, amount_on_blockchain)
        list_txs.return_value = [{
            'account': '',
            'address': order.withdraw_address.address,
            'category': 'send',
            'amount': -amount_on_blockchain,
            'txid': self.generate_txn_id(),
        }]
        scrypt_health.return_value = {}
        order.refresh_from_db()
        order.pair.base.refresh_from_db()
        with self.assertRaises(ValidationError):
            scrypt.assert_tx_unique(
                order.pair.base, order.withdraw_address, order.amount_base
            )
        order_legacy.refresh_from_db()
        order_legacy.pair.base.refresh_from_db()
        with self.assertRaises(ValidationError):
            scrypt.assert_tx_unique(
                order_legacy.pair.base, order_legacy.withdraw_address,
                order_legacy.amount_base
            )
        self.assertEqual(order.status, order.PAID)
        exchange_order_release_periodic.apply_async()
        order.refresh_from_db()
        self.assertEqual(order.status, order.PRE_RELEASE)
        release_coins.assert_not_called()
        self.assertTrue(order.flagged)
예제 #6
0
 def test_input_amount_also_formatted(self, rounding):
     input_amount = Decimal('0.12345678')
     pair_name = 'BTCLTC'
     pair = Pair.objects.get(name=pair_name)
     pair.quote.rounding = rounding
     pair.quote.save()
     pair.base.rounding = rounding
     pair.base.save()
     base_order = self._create_order_api(pair_name=pair_name,
                                         amount_base=input_amount)
     self.assertEqual(
         base_order.amount_base,
         money_format(input_amount, places=rounding)
     )
     quote_order = self._create_order_api(pair_name=pair_name,
                                          amount_quote=input_amount)
     self.assertEqual(
         quote_order.amount_quote,
         money_format(input_amount, places=rounding)
     )
예제 #7
0
 def get_rate(cls, base, quote):
     inverted = False
     base = cls._get_currency(base)
     quote = cls._get_currency(quote)
     if base == quote:
         return Decimal('1.0')
     places = 16
     if all([not base.is_crypto, quote.is_crypto]):
         base, quote = quote, base
         inverted = True
         places = 16
     elif all([not base.is_crypto, not quote.is_crypto]):
         places = 16
     try:
         pair = Pair.objects.get(base=base, quote=quote)
         if pair.disable_ticker:
             # only return values if ticker is not disabled
             return
         latest_rate = cls.objects.filter(
             pair=pair,
             market__is_main_market=True).latest('id').ticker.rate
         if inverted:
             latest_rate = money_format(Decimal(1.0) / latest_rate,
                                        places=places)
     except Pair.DoesNotExist:
         latest_btc = cls.objects.filter(
             pair__name='BTC{}'.format(quote.code),
             market__is_main_market=True).latest('id').ticker.rate
         latest_base = cls.objects.filter(
             pair__name='BTC{}'.format(base.code),
             market__is_main_market=True).latest('id').ticker.rate
         if inverted:
             latest_rate = money_format(latest_base / latest_btc,
                                        places=places)
         else:
             latest_rate = money_format(latest_btc / latest_base,
                                        places=places)
     return latest_rate
예제 #8
0
 def assert_tx_unique(self, currency, address, amount, **kwargs):
     res = self._list_txs(
         currency.wallet,
         tx_count=settings.RPC_IMPORT_TRANSACTIONS_VALIDATION_COUNT
     )
     _address = getattr(address, 'address', address)
     _places = currency.rounding
     same_amount_txs = [
         t for t in res if
         t['category'] == 'send' and
         t['address'] == _address and
         money_format(
             t['amount'], places=_places
         ) == -money_format(amount, places=_places)
     ]
     if same_amount_txs:
         raise ValidationError(
             'Transaction of {amount} {currency} to {address} already '
             'exist. Tx list: {tx_list} '.format(
                 amount=amount,
                 address=_address,
                 currency=currency.code,
                 tx_list=same_amount_txs
             ))
예제 #9
0
 def test_create_order_when_amount_decimals_are_exceeded(self):
     amount_base = Decimal('0.12345678910222')
     response = self._create_order_api(amount=amount_base)
     self.assertEqual(response.status_code, 201,
                      'order wasn\'t created, reason: {}'
                      .format(response.json()))
     order = Order.objects.latest('pk')
     amount_base_formatted = money_format(amount_base, places=8)
     self.assertEqual(order.amount_base, amount_base_formatted)
     amount_base = Decimal('0.1234')
     response = self._create_order_api(amount=amount_base)
     self.assertEqual(response.status_code, 201,
                      'order wasn\'t created, reason: {}'
                      .format(response.json()))
     order = Order.objects.latest('pk')
     self.assertEqual(order.amount_base, amount_base)
예제 #10
0
    def generate_cachier_url_for_order(self, order):
        url = self.api.url.format('purchase')
        _ref = order.unique_reference

        key = settings.SAFE_CHARGE_SECRET_KEY
        merchant_id = settings.SAFE_CHARGE_MERCHANT_ID
        merchant_site_id = settings.SAFE_CHARGE_MERCHANT_SITE_ID
        currency = order.pair.quote.code
        amount = str(money_format(order.amount_quote, places=2))
        total_amount = item_amount_1 = amount
        email = 'user{}@n.exchange'.format(order.user.pk)
        item_name_1 = _ref
        item_quantity_1 = '1'
        user_token = 'auto'
        version = '4.0.0'
        user_token_id = order.user.username
        notify_url = settings.SAFE_CHARGE_NOTIFY_URL
        success_url = settings.SAFE_CHARGE_SUCCESS_URL.format(_ref)
        pending_url = settings.SAFE_CHARGE_PENDING_URL.format(_ref)
        error_url = settings.SAFE_CHARGE_ERROR_URL.format(_ref)
        back_url = settings.SAFE_CHARGE_BACK_URL.format(_ref)
        time_stamp = datetime.now().strftime("%Y-%m-%d.%H:%M:%S")
        to_hash = (key, merchant_site_id, merchant_id, currency, total_amount,
                   email, item_name_1, item_amount_1, item_quantity_1,
                   user_token, version, user_token_id, success_url,
                   pending_url, error_url, back_url, notify_url, time_stamp)
        checksum = get_sha256_sign(ar_hash=to_hash, delimiter='', upper=False)
        params = \
            '?merchant_site_id={merchant_site_id}' \
            '&merchant_id={merchant_id}' \
            '&currency={currency}' \
            '&total_amount={total_amount}' \
            '&email={email}' \
            '&item_name_1={item_name_1}' \
            '&item_amount_1={item_amount_1}' \
            '&item_quantity_1={item_quantity_1}' \
            '&user_token={user_token}' \
            '&version={version}' \
            '&user_token_id={user_token_id}' \
            '&success_url={success_url}' \
            '&pending_url={pending_url}' \
            '&error_url={error_url}' \
            '&back_url={back_url}' \
            '&notify_url={notify_url}' \
            '&time_stamp={time_stamp}' \
            '&checksum={checksum}'.format(
                merchant_site_id=merchant_site_id,
                merchant_id=merchant_id,
                time_stamp=time_stamp,
                total_amount=total_amount,
                email=quote(email),
                currency=currency,
                checksum=checksum,
                item_name_1=item_name_1,
                item_amount_1=item_amount_1,
                item_quantity_1=item_quantity_1,
                user_token_id=user_token_id,
                user_token=user_token,
                version=version,
                success_url=quote(success_url),
                pending_url=quote(pending_url),
                error_url=quote(error_url),
                back_url=quote(back_url),
                notify_url=quote(notify_url)
            )
        url = url + params
        return url
예제 #11
0
 def print_orders(self, orders):
     print(
         '#', 'date', 'time', 'order_ref', 'pair', 'amount_quote', 'quote_code',
         'amount_base', 'base_code', 'markup_fee_quote', 'with_fee_quote',
         'deposit_fee_quote', 'markup_fee_base', 'with_fee_base',
         'deposit_fee_base',
         'with_markup_from_db', 'deposit_tx_id', 'withdraw_tx_id'
     )
     tot_with_quote = tot_dep_quote = tot_markup_quote = Decimal('0')
     tot_with_base = tot_dep_base = tot_markup_base = Decimal('0')
     tot_amount_base = tot_amount_quote = Decimal('0')
     for i, order in enumerate(orders):
         with_tx_id = order.transactions.get(type='W').tx_id
         dep_tx_id = order.transactions.get(type='D').tx_id
         fees = order.orderfee_set.all()
         with_markup_fees_from_db = False
         if fees:
             with_fee = fees.get(fee_source__name='Withdrawal')
             markup_fee = fees.get(fee_source__name='Markup')
             with_fee_quote = with_fee.amount_quote
             with_fee_base = with_fee.amount_base
             markup_fee_quote = markup_fee.amount_quote
             markup_fee_base = markup_fee.amount_base
             with_markup_fees_from_db = True
         else:
             with_fee_base = order.withdrawal_fee
             with_fee_quote = order.withdrawal_fee_quote
             markup_multiplier = \
                 Decimal('1') / (Decimal('1') + order.pair.fee_ask) \
                 * order.pair.fee_ask
             markup_fee_quote = money_format(
                 (order.amount_quote - with_fee_quote) * markup_multiplier,
                 places=8
             )
             markup_fee_base = money_format(
                 (order.amount_base - with_fee_base) * markup_multiplier,
                 places=8
             )
             with_fee_base = money_format(with_fee_base, places=8)
             with_fee_quote = money_format(with_fee_quote, places=8)
         if order.pair.quote.code == 'ETH':
             # Ethereum wallet transfer fee
             deposit_fee_quote = Decimal('0.00105')
         elif order.pair.quote.code == 'BTC':
             # bittrex withdrawal fee
             deposit_fee_quote = Decimal('0.0005')
         elif order.pair.quote.code == 'DOGE':
             # bittrex withdrawal fee
             deposit_fee_quote = Decimal('2')
         elif order.pair.quote.code == 'LTC':
             # bittrex withdrawal fee
             deposit_fee_quote = Decimal('0.01')
         deposit_fee_base = money_format(
             deposit_fee_quote * with_fee_base / with_fee_quote,
             places=8
         )
         print(
             i + 1, order.created_on, order.unique_reference, order.pair.name,
             order.amount_quote, order.pair.quote.code, order.amount_base,
             order.pair.base.code, markup_fee_quote, with_fee_quote,
             deposit_fee_quote, markup_fee_base, with_fee_base,
             deposit_fee_base, with_markup_fees_from_db, with_tx_id,
             dep_tx_id
         )
         tot_dep_quote += deposit_fee_quote
         tot_dep_base += deposit_fee_base
         tot_markup_quote += markup_fee_quote
         tot_markup_base += markup_fee_base
         tot_with_quote += with_fee_quote
         tot_with_base += with_fee_base
         tot_amount_base += order.amount_base
         tot_amount_quote += order.amount_quote
     tot_fees_quote = tot_dep_quote + tot_markup_quote + tot_with_quote
     tot_fees_base = tot_dep_base + tot_markup_base + tot_with_base
     print()
     print(
         'Total {count} {pair} orders.Volume {tot_amount_base}{base}'
         '({tot_amount_quote}{quote}). Total fees '
         '{tot_fees_quote}{quote}({tot_fees_base}{base}): withdrawal fees '
         '{with_fees_quote}{quote}({with_fees_base}{base}), deposit fees '
         '{dep_fees_quote}{quote}({dep_fees_base}{base}), markup fees '
         '{markup_fees_quote}{quote}({markup_fees_base}{base})'.format(
             count=orders.count(),
             pair=order.pair.name,
             tot_fees_quote=tot_fees_quote,
             tot_fees_base=tot_fees_base,
             quote=order.pair.quote.code,
             with_fees_quote=tot_with_quote,
             with_fees_base=tot_with_base,
             dep_fees_quote=tot_dep_quote,
             dep_fees_base=tot_dep_base,
             markup_fees_quote=tot_markup_quote,
             markup_fees_base=tot_markup_base,
             base=order.pair.base.code,
             tot_amount_base=tot_amount_base,
             tot_amount_quote=tot_amount_quote
         )
     )
     print()
     base = order.pair.base.code
     quote = order.pair.quote.code
     print('fee_name', 'quote({})'.format(quote), 'base({})'.format(base))
     print('Markup', tot_markup_quote, tot_markup_base)
     print('Withdrawal', tot_with_quote, tot_with_base)
     print('Deposit', tot_dep_quote, tot_dep_base)
     print('Total', tot_fees_quote, tot_fees_base)
     print()
     print('Volume_quote({})'.format(quote), 'Volume_base({})'.format(base))
     print(tot_amount_quote, tot_amount_base)
     print()
     print()
     return {
         order.pair.name: {
             'positions': {
                 base: tot_amount_base, quote: -tot_amount_quote
             },
             'fees': {base: tot_fees_base, quote: tot_fees_quote},
             'deposit_fees': {quote: tot_dep_quote}
         }}
예제 #12
0
 def average_position_price(self):
     if self.base_position and self.position:
         return money_format(abs(self.base_position / self.position),
                             places=8)
예제 #13
0
 def volume_rate_change(self):
     if self.acquisition_rate and self.rate and self.volume_position_ratio:
         res = \
             (self.rate - self.acquisition_rate) \
             / self.rate / self.volume_position_ratio
         return money_format(res, places=8)
예제 #14
0
 def static_rate_change(self):
     if self.acquisition_rate and self.rate:
         return money_format(
             (self.rate - self.acquisition_rate) / self.rate, places=8)
예제 #15
0
 def rate(self):
     if self.amount_quote and self.amount_base:
         return money_format(abs(self.amount_base / self.amount_quote),
                             places=8)