Skip to content

Commit

Permalink
Recommitted as new branch with unit tests - GIT screwd me on the last PR
Browse files Browse the repository at this point in the history
  • Loading branch information
creslinux committed Jul 30, 2018
1 parent f832edf commit 012fe94
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
31 changes: 31 additions & 0 deletions freqtrade/exchange/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from random import randint
from typing import List, Dict, Any, Optional
from datetime import datetime
from math import floor, ceil

import ccxt
import arrow
Expand Down Expand Up @@ -150,6 +151,28 @@ def exchange_has(self, endpoint: str) -> bool:
"""
return endpoint in self._api.has and self._api.has[endpoint]

def symbol_amount_prec(self, pair, amount: float):
'''
Returns the amount to buy or sell to a precision the Exchange accepts
Rounded down
'''
if self._api.markets[pair]['precision']['amount']:
symbol_prec = self._api.markets[pair]['precision']['amount']
big_amount = amount * pow(10, symbol_prec)
amount = floor(big_amount) / pow(10, symbol_prec)
return amount

def symbol_price_prec(self, pair, price: float):
'''
Returns the price buying or selling with to the precision the Exchange accepts
Rounds up
'''
if self._api.markets[pair]['precision']['price']:
symbol_prec = self._api.markets[pair]['precision']['price']
big_price = price * pow(10, symbol_prec)
price = ceil(big_price) / pow(10, symbol_prec)
return price

def buy(self, pair: str, rate: float, amount: float) -> Dict:
if self._conf['dry_run']:
order_id = f'dry_run_buy_{randint(0, 10**6)}'
Expand All @@ -167,6 +190,10 @@ def buy(self, pair: str, rate: float, amount: float) -> Dict:
return {'id': order_id}

try:
# Set the precision for amount and price(rate) as accepted by the exchange
amount = self.symbol_amount_prec(pair, amount)
rate = self.symbol_price_prec(pair, rate)

return self._api.create_limit_buy_order(pair, amount, rate)
except ccxt.InsufficientFunds as e:
raise DependencyException(
Expand Down Expand Up @@ -200,6 +227,10 @@ def sell(self, pair: str, rate: float, amount: float) -> Dict:
return {'id': order_id}

try:
# Set the precision for amount and price(rate) as accepted by the exchange
amount = self.symbol_amount_prec(pair, amount)
rate = self.symbol_price_prec(pair, rate)

return self._api.create_limit_sell_order(pair, amount, rate)
except ccxt.InsufficientFunds as e:
raise DependencyException(
Expand Down
48 changes: 47 additions & 1 deletion freqtrade/tests/exchange/test_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,52 @@ def test_init_exception(default_conf, mocker):
Exchange(default_conf)


def test_symbol_amount_prec(default_conf, mocker):
'''
Test rounds down to 4 Decimal places
'''
api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
})
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='binance'))

markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'amount': 4}}})
type(api_mock).markets = markets

mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
exchange = Exchange(default_conf)

amount = 2.34559
pair = 'ETH/BTC'
amount = exchange.symbol_amount_prec(pair, amount)
assert amount == 2.3455


def test_symbol_price_prec(default_conf, mocker):
'''
Test rounds up to 4 decimal places
'''
api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
})
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='binance'))

markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': 4}}})
type(api_mock).markets = markets

mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
exchange = Exchange(default_conf)

price = 2.34559
pair = 'ETH/BTC'
price = exchange.symbol_price_prec(pair, price)
assert price == 2.3456


def test_validate_pairs(default_conf, mocker):
api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={
Expand Down Expand Up @@ -173,7 +219,7 @@ def test_validate_timeframes_not_in_config(default_conf, mocker):
Exchange(default_conf)


def test_exchange_has(default_conf, mocker):
def test_exchangehas(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf)
assert not exchange.exchange_has('ASDFASDF')
api_mock = MagicMock()
Expand Down

0 comments on commit 012fe94

Please sign in to comment.