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)
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
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
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
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)
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) )
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
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 ))
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)
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}' \ '¤cy={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}' \ '¬ify_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
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} }}
def average_position_price(self): if self.base_position and self.position: return money_format(abs(self.base_position / self.position), places=8)
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)
def static_rate_change(self): if self.acquisition_rate and self.rate: return money_format( (self.rate - self.acquisition_rate) / self.rate, places=8)
def rate(self): if self.amount_quote and self.amount_base: return money_format(abs(self.amount_base / self.amount_quote), places=8)