def get_withdraw_limit_data(account, include_pending_requests=True): from currencies.money import Money withdraw_limit = Decimal(account.balance_money.amount) # subtract money which already waiting for output if include_pending_requests: # TODO: why the f I use last group here? Should we just take all requests? group = WithdrawRequestsGroup.objects.filter( account=account, is_closed=False).last() if group: withdraw_requests = group.requests.filter(is_committed=None) if withdraw_requests: withdraw_requests_amount = 0 for withdraw_request in withdraw_requests: withdraw_requests_amount += Decimal( withdraw_request.amount_money.to( account.currency).amount) withdraw_limit -= Decimal(withdraw_requests_amount) # Note: displaying a negative upper bound doesn't make sense, # so we round balance to zero in that case. withdraw_limit = max(0, withdraw_limit) # drop digits beyond needed precision withdraw_limit = currencies.round_floor(withdraw_limit) return Money(withdraw_limit, account.currency), Money(0, account.currency)
def test_get_for_currencies_multiple_currencies(self): currencies = [Mock(), Mock()] moneys = [Money(10, currencies[0]), Money(-8, currencies[1])] balance = Balance(moneys) assert balance.get_for_currency(currencies[0]) == Money( 10, currencies[0]) assert balance.get_for_currency(currencies[1]) == Money( -8, currencies[1])
def test_fails_on_unbalanced_movements_and_single_account(self): self.data_update(movements_specs=[ MovementSpec(self.accs[0], Money(100, self.cur)), MovementSpec(self.accs[1], Money(-99, self.cur)) ]) errmsg = TransactionMovementSpecListValidator\ .ERR_MSGS['UNBALANCED_SINGLE_CURRENCY'] self.assertRaisesMessage(ValidationError, errmsg, self.call)
def test_should_create_new_instances_on_comparisons(self): a, b = Money(100, 'USD'), Money(3, 'USD') ab_ids = map(id, [a, b]) self.assertNotIn(id(a > b), ab_ids) self.assertNotIn(id(a < b), ab_ids) self.assertNotIn(id(a >= b), ab_ids) self.assertNotIn(id(a <= b), ab_ids) self.assertNotIn(id(a == b), ab_ids) self.assertNotIn(id(a != b), ab_ids)
def test_from_data_base(self): trans = self.create() assert trans.get_description() == self.data['description'] assert trans.get_date() == self.data['date'] movements = trans.get_movements_specs() assert movements == [ MovementSpec(self.accs[0], Money(10, self.curs[0])), MovementSpec(self.accs[1], Money(-8, self.curs[1])), ]
def test_fails_if_movements_have_a_single_acc(self): self.data_update(movements_specs=[ MovementSpec(self.accs[0], Money(100, self.cur)), MovementSpec(self.accs[0], Money(-100, self.cur)) ]) errmsg = TransactionMovementSpecListValidator.ERR_MSGS[ 'SINGLE_ACCOUNT'] with self.assertRaisesMessage(ValidationError, errmsg): self.call()
def test_fails_if_duplicated_currency_account_pair(self): self.data_update(movements_specs=[ MovementSpec(self.accs[0], Money(1, self.cur)), MovementSpec(self.accs[0], Money(1, self.cur)), MovementSpec(self.accs[1], Money(-2, self.cur)) ]) errmsg = TransactionMovementSpecListValidator.ERR_MSGS[ "REPEATED_CURRENCY_ACCOUNT_PAIR"] with self.assertRaisesMessage(ValidationError, errmsg): self.call()
def test_base(self): currency = CurrencyTestFactory() account = AccountTestFactory() other_acc = AccountTestFactory() transaction_with = TransactionTestFactory(movements_specs=[ MovementSpec(account, Money('10', currency)), MovementSpec(other_acc, Money('-10', currency)), ]) transaction_without = TransactionTestFactory.create() assert list(Transaction.objects.filter_by_account(account)) ==\ [transaction_with]
def test_serializes_as_list_of_moneys(self, m_to_representation): currency_one, currency_two = Mock(), Mock() balance = Mock() balance.get_moneys.return_value = [ Money('20', currency_one), Money('30', currency_two), ] serializer = BalanceSerializer(balance) assert serializer.data == [m_to_representation.return_value] * 2 assert m_to_representation.call_args_list[0] ==\ call(Money('20', currency_one)) assert m_to_representation.call_args_list[1] ==\ call(Money('30', currency_two))
def test_get_balances(self): currency_one, currency_two = Mock(), Mock() transactions = [ self.gen_transaction_mock([Money('10', currency_one)]), self.gen_transaction_mock([Money('20', currency_two)]) ] initial_balance = Balance([Money('20', currency_two)]) journal = Journal(Mock(), initial_balance, transactions) result = journal.get_balances() assert result[0] == initial_balance.add_money(Money( '10', currency_one)) assert result[1] == result[0].add_money(Money('20', currency_two))
def test_post_single_transaction(self): resp = self.client.post('/transactions/', self.post_data) assert resp.status_code == 201, resp.data assert resp.json()['date'] == '2018-12-21' assert resp.json()['description'] == self.post_data['description'] obj = Transaction.objects.get(pk=resp.json()['pk']) assert obj.get_description() == 'A' assert obj.date == date(2018, 12, 21) assert obj.get_movements_specs() == [ MovementSpec(self.accs[0], Money(200, self.cur)), MovementSpec(self.accs[1], Money(-200, self.cur)) ]
def test_patch_transaction_with_single_currency_but_unmatched_values_err(self): # Same currency, unmatched values! trans = TransactionTestFactory() moneys = [Money(100, self.cur), Money(-98, self.cur)] movements_specs = [MovementSpecTestFactory(money=m) for m in moneys] resp = self.client.patch( f'/transactions/{trans.pk}/', {'movements_specs': [ MovementSpecSerializer(m).data for m in movements_specs ]} ) assert resp.status_code == 400 assert 'movements_specs' in resp.json() err = TransactionMovementSpecListValidator.\ ERR_MSGS['UNBALANCED_SINGLE_CURRENCY'] assert err in resp.json()['movements_specs']
def get_balance_money(self, with_bonus=False): from platforms.cfh.exceptions import CFHError from platforms.strategy_store.exceptions import SSError # type: (bool) -> Money try: return Money(*self.get_balance(with_bonus=with_bonus)) except (CFHError, SSError): return NoneMoney()
def setUp(self): super().setUp() self.date_ = date(2017, 12, 24) self.accs = [ AccountFactory()("A", AccTypeEnum.LEAF, get_root_acc()), AccountFactory()("B", AccTypeEnum.LEAF, get_root_acc()) ] # Force second money to exactly offset the first. self.cur = CurrencyTestFactory() self.moneys = [Money(100, self.cur), Money(-100, self.cur)] self.data = { "description": "Hola", "date_": self.date_, "movements_specs": [MovementSpec(a, m) for a, m in zip(self.accs, self.moneys)] }
def requests_sum_total(self): if not self.account.currency: raise RuntimeError( 'Cannot display account {0} withdraw requests summ, because account currency is {0}' .format(self.account, type(self.account.currency))) currency = 'USD' if self.account.currency.is_metal else self.account.currency amount = sum([ wr.amount_money.to(currency).amount for wr in self.alive_requests ], 0) return Money(amount, currency)
def equity_money(self): # type: () -> Money """ Return account equity (value of open positions + balance) Returns Money object. """ try: return Money(self.api.account_equity(self), self.currency) except PlatformError as e: return NoneMoney()
def setUp(self): super().setUp() self.accs = AccountTestFactory.create_batch(3, acc_type=AccTypeEnum.LEAF) self.curs = CurrencyTestFactory.create_batch(2) self.moneys = [Money(10, self.curs[0]), Money(-8, self.curs[1])] self.movements_specs = [ MovementSpec(self.accs[0], self.moneys[0]), MovementSpec(self.accs[1], self.moneys[1]) ] self.data = { 'description': 'hola', 'date': date(1993, 11, 23), 'movements_specs': [ MovementSpecSerializer(self.movements_specs[0]).data, MovementSpecSerializer(self.movements_specs[1]).data ] }
def test_set_movements_base(self): cur = CurrencyTestFactory() values = ((Decimal(1) / Decimal(3)), (Decimal(2) / Decimal(3)), Decimal(-1)) moneys = [Money(val, cur) for val in values] accs = AccountTestFactory.create_batch(3) mov_specs = [ MovementSpec(acc, money) for acc, money in zip(accs, moneys) ] trans = TransactionTestFactory() assert trans.get_movements_specs() != mov_specs trans.set_movements(mov_specs) assert trans.get_movements_specs() == mov_specs
def setUp(self): super().setUp() # Some default data for the post request self.populate_accounts() self.accs = AccountTestFactory.create_batch( 2, acc_type=AccTypeEnum.LEAF ) self.cur = CurrencyTestFactory() self.moneys = [Money(200, self.cur), Money(-200, self.cur)] self.movements_specs = [ MovementSpec(self.accs[0], self.moneys[0]), MovementSpec(self.accs[1], self.moneys[1]) ] self.post_data = { 'description': 'A', 'date': date(2018, 12, 21), 'movements_specs': [ MovementSpecSerializer(self.movements_specs[0]).data, MovementSpecSerializer(self.movements_specs[1]).data ] }
def requests_sum_stats(self): if not self.account.currency: raise RuntimeError( 'Cannot display account {0} withdraw requests summ, because account currency is {0}' .format(self.account, type(self.account.currency))) with Money.convert_cache_key('autonosick_{0}'.format( date.today().strftime("%d/%m/%Y"))): stats = dict() for wr in self.alive_requests: m = wr.amount_money if wr.payment_system in stats: m = m.to(stats[wr.payment_system].currency) if wr.payment_system not in stats: stats[wr.payment_system] = m else: stats[wr.payment_system] += m return { payment_system: { 'money': money, 'need_check': amount_needs_check(payment_system, money) } for payment_system, money in stats.items() }
def test_patch_transaction(self): accs = AccountTestFactory.create_batch( 3, acc_type=AccTypeEnum.LEAF ) cur = CurrencyTestFactory() trans = TransactionTestFactory() new_movements = [MovementSpecSerializer(x).data for x in ( MovementSpec(accs[0], Money(100, cur)), MovementSpec(accs[1], Money(50, cur)), MovementSpec(accs[2], Money(-150, cur)) )] resp = self.client.patch( f'/transactions/{trans.pk}/', {'movements_specs': new_movements} ) assert resp.status_code == 200, resp.data trans.refresh_from_db() movements = trans.get_movements_specs() assert len(movements) == 3 assert [x.money for x in movements] == \ [Money(100, cur), Money(50, cur), Money(-150, cur)]
def test_check_balance_and_add_transaction(self): # The user has two accounts he uses, with two transactions between them cur = CurrencyTestFactory() accs = AccountTestFactory.create_batch(2, acc_type=AccTypeEnum.LEAF) transactions = [ TransactionTestFactory(date_=date(2018, 1, 2), movements_specs=[ MovementSpec(accs[0], Money(100, cur)), MovementSpec(accs[1], Money(-100, cur)) ]), TransactionTestFactory(date_=date(2018, 1, 1), movements_specs=[ MovementSpec(accs[0], Money(22, cur)), MovementSpec(accs[1], Money(-22, cur)) ]) ] transactions.sort(key=lambda x: x.get_date(), reverse=True) serialized_transactions = \ TransactionSerializer(transactions, many=True).data # He also has another two accounts with an unrelated transaction other_accs = AccountTestFactory.create_batch(2, acc_type=AccTypeEnum.LEAF) TransactionTestFactory(date_=date(2017, 1, 2), movements_specs=[ MovementSpec(other_accs[0], Money(100, cur)), MovementSpec(other_accs[1], Money(-100, cur)) ]) # He queries ony for transactions involving acc1, and see the # same ones listed, in chronological order assert self.get_json(f"{URLS.transaction}?account_id={accs[0].pk}") == \ serialized_transactions # He adds a new transaction of 10 cur to acc2 new_transaction = self.post_json( URLS.transaction, { "description": "New Transaction", "date": "2018-01-03", "movements_specs": [{ "account": accs[0].pk, "money": { "quantity": 10, "currency": cur.pk } }, { "account": accs[1].pk, "money": { "quantity": -10, "currency": cur.pk } }] }) serialized_transactions.insert(0, new_transaction) # He queries again for transactions involving acc1, and see all # of them listed assert self.get_json(f"{URLS.transaction}?account_id={accs[0].pk}") == \ serialized_transactions
def get_referral_money(self): return Money(sum(map(lambda r: float(r.api.account_balance(r) or 0), self.agent_accounts.non_demo_active())) \ if self.is_ib else 0, USD)
def test_base(self): currency = Mock() money = Money('10.24', currency) assert money.quantity == Decimal('10.24') assert money.currency == currency
def test_equal_false_diff_quantities(self): currency = Mock() one = Balance([Money('10', currency)]) two = Balance([Money('9', currency)]) assert one != two
def test_equal_false_diff_currencies(self): currencies = [Mock(), Mock()] one = Balance([Money('10', currencies[0])]) two = Balance([Money('10', currencies[1])]) assert one != two
def test_equal_true(self): currency = Mock() one = Balance([Money('10', currency)]) two = Balance([Money('7', currency), Money('3', currency)]) assert one == two
def test_get_currencies_base(self): currencies = [Mock(), Mock()] balance = Balance( [Money('11', currencies[0]), Money('7', currencies[1])]) assert balance.get_currencies() == set(currencies)
def test_get_for_currency_present_two_movements(self): currency = Mock() moneys = [Money(10, currency), Money(20, currency)] balance = Balance(moneys) assert balance.get_for_currency(currency) == Money(30, currency)
def test_get_for_currency_not_present_return_zero(self): currencies = [Mock(), Mock()] money = Money(10, currencies[0]) balance = Balance([money]) assert balance.get_for_currency(currencies[1]) == Money( 0, currencies[1])