Display profits in fiat

This commit is contained in:
Gerald Lonlas 2017-12-24 23:51:41 -08:00
parent 433bf409f4
commit ff6b0fc1c9
12 changed files with 400 additions and 27 deletions

View File

@ -55,6 +55,12 @@ use the `last` price and values between those interpolate between ask and last
price. Using `ask` price will guarantee quick success in bid, but bot will also price. Using `ask` price will guarantee quick success in bid, but bot will also
end up paying more then would probably have been necessary. end up paying more then would probably have been necessary.
`fiat_currency` set the fiat to use for the conversion form coin to
fiat in Telegram. The valid value are: "AUD", "BRL", "CAD", "CHF",
"CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS",
"INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN",
"RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD".
The other values should be self-explanatory, The other values should be self-explanatory,
if not feel free to raise a github issue. if not feel free to raise a github issue.

View File

@ -2,6 +2,7 @@
"max_open_trades": 3, "max_open_trades": 3,
"stake_currency": "BTC", "stake_currency": "BTC",
"stake_amount": 0.05, "stake_amount": 0.05,
"fiat_display_currency": "USD",
"dry_run": false, "dry_run": false,
"minimal_roi": { "minimal_roi": {
"40": 0.0, "40": 0.0,

156
freqtrade/fiat_convert.py Normal file
View File

@ -0,0 +1,156 @@
import logging
import time
from pymarketcap import Pymarketcap
logger = logging.getLogger(__name__)
class CryptoFiat():
# Constants
CACHE_DURATION = 6 * 60 * 60 # 6 hours
def __init__(self, crypto_symbol: str, fiat_symbol: str, price: float) -> None:
"""
Create an object that will contains the price for a crypto-currency in fiat
:param crypto_symbol: Crypto-currency you want to convert (e.g BTC)
:param fiat_symbol: FIAT currency you want to convert to (e.g USD)
:param price: Price in FIAT
"""
# Public attributes
self.crypto_symbol = None
self.fiat_symbol = None
self.price = 0.0
# Private attributes
self._expiration = 0
self.crypto_symbol = crypto_symbol.upper()
self.fiat_symbol = fiat_symbol.upper()
self.set_price(price=price)
def set_price(self, price: float) -> None:
"""
Set the price of the Crypto-currency in FIAT and set the expiration time
:param price: Price of the current Crypto currency in the fiat
:return: None
"""
self.price = price
self._expiration = time.time() + self.CACHE_DURATION
def is_expired(self) -> bool:
"""
Return if the current price is still valid or needs to be refreshed
:return: bool, true the price is expired and needs to be refreshed, false the price is
still valid
"""
return self._expiration - time.time() <= 0
class CryptoToFiatConverter():
# Constants
SUPPORTED_FIAT = [
"AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK",
"EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY",
"KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN",
"RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD"
]
def __init__(self) -> None:
self._coinmarketcap = Pymarketcap()
self._pairs = []
def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float:
"""
Convert an amount of crypto-currency to fiat
:param crypto_amount: amount of crypto-currency to convert
:param crypto_symbol: crypto-currency used
:param fiat_symbol: fiat to convert to
:return: float, value in fiat of the crypto-currency amount
"""
price = self.get_price(crypto_symbol=crypto_symbol, fiat_symbol=fiat_symbol)
return float(crypto_amount) * float(price)
def get_price(self, crypto_symbol: str, fiat_symbol: str) -> float:
"""
Return the price of the Crypto-currency in Fiat
:param crypto_symbol: Crypto-currency you want to convert (e.g BTC)
:param fiat_symbol: FIAT currency you want to convert to (e.g USD)
:return: Price in FIAT
"""
crypto_symbol = crypto_symbol.upper()
fiat_symbol = fiat_symbol.upper()
# Check if the fiat convertion you want is supported
if not self._is_supported_fiat(fiat=fiat_symbol):
raise ValueError('The fiat {} is not supported.'.format(fiat_symbol))
# Get the pair that interest us and return the price in fiat
for pair in self._pairs:
if pair.crypto_symbol == crypto_symbol and pair.fiat_symbol == fiat_symbol:
# If the price is expired we refresh it, avoid to call the API all the time
if pair.is_expired():
pair.set_price(
price=self._find_price(
crypto_symbol=pair.crypto_symbol,
fiat_symbol=pair.fiat_symbol
)
)
# return the last price we have for this pair
return pair.price
# The pair does not exist, so we create it and return the price
return self._add_pair(
crypto_symbol=crypto_symbol,
fiat_symbol=fiat_symbol,
price=self._find_price(
crypto_symbol=crypto_symbol,
fiat_symbol=fiat_symbol
)
)
def _add_pair(self, crypto_symbol: str, fiat_symbol: str, price: float) -> float:
"""
:param crypto_symbol: Crypto-currency you want to convert (e.g BTC)
:param fiat_symbol: FIAT currency you want to convert to (e.g USD)
:return: price in FIAT
"""
self._pairs.append(
CryptoFiat(
crypto_symbol=crypto_symbol,
fiat_symbol=fiat_symbol,
price=price
)
)
return price
def _is_supported_fiat(self, fiat: str) -> bool:
"""
Check if the FIAT your want to convert to is supported
:param fiat: FIAT to check (e.g USD)
:return: bool, True supported, False not supported
"""
fiat = fiat.upper()
return fiat in self.SUPPORTED_FIAT
def _find_price(self, crypto_symbol: str, fiat_symbol: str) -> float:
"""
Call CoinMarketCap API to retrieve the price in the FIAT
:param crypto_symbol: Crypto-currency you want to convert (e.g BTC)
:param fiat_symbol: FIAT currency you want to convert to (e.g USD)
:return: float, price of the crypto-currency in Fiat
"""
# Check if the fiat convertion you want is supported
if not self._is_supported_fiat(fiat=fiat_symbol):
raise ValueError('The fiat {} is not supported.'.format(fiat_symbol))
return float(
self._coinmarketcap.ticker(
currency=crypto_symbol,
convert=fiat_symbol
)['price_' + fiat_symbol.lower()]
)

View File

@ -17,6 +17,7 @@ from freqtrade.analyze import get_signal, SignalType
from freqtrade.misc import State, get_state, update_state, parse_args, throttle, \ from freqtrade.misc import State, get_state, update_state, parse_args, throttle, \
load_config load_config
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.fiat_convert import CryptoToFiatConverter
logger = logging.getLogger('freqtrade') logger = logging.getLogger('freqtrade')
@ -119,14 +120,28 @@ def execute_sell(trade: Trade, limit: float) -> None:
trade.open_order_id = order_id trade.open_order_id = order_id
fmt_exp_profit = round(trade.calc_profit_percent(rate=limit) * 100, 2) fmt_exp_profit = round(trade.calc_profit_percent(rate=limit) * 100, 2)
rpc.send_msg('*{}:* Selling [{}]({}) with limit `{:.8f} (profit: ~{:.2f}%, {:.8f})`'.format( profit_trade = trade.calc_profit(rate=limit)
trade.exchange,
trade.pair.replace('_', '/'), fiat_converter = CryptoToFiatConverter()
exchange.get_pair_detail_url(trade.pair), profit_fiat = fiat_converter.convert_amount(
limit, profit_trade,
fmt_exp_profit, _CONF['stake_currency'],
trade.calc_profit(rate=limit), _CONF['fiat_display_currency']
)) )
rpc.send_msg('*{exchange}:* Selling [{pair}]({pair_url}) with limit `{limit:.8f}`'
'` (profit: ~{profit_percent:.2f}%, {profit_coin:.8f} {coin}`'
'` / {profit_fiat:.3f} {fiat})`'.format(
exchange=trade.exchange,
pair=trade.pair.replace('_', '/'),
pair_url=exchange.get_pair_detail_url(trade.pair),
limit=limit,
profit_percent=fmt_exp_profit,
profit_coin=profit_trade,
coin=_CONF['stake_currency'],
profit_fiat=profit_fiat,
fiat=_CONF['fiat_display_currency'],
))
Trade.session.flush() Trade.session.flush()

View File

@ -208,6 +208,7 @@ CONF_SCHEMA = {
'max_open_trades': {'type': 'integer', 'minimum': 1}, 'max_open_trades': {'type': 'integer', 'minimum': 1},
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']}, 'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']},
'stake_amount': {'type': 'number', 'minimum': 0.0005}, 'stake_amount': {'type': 'number', 'minimum': 0.0005},
'fiat_display_currency': {'type': 'string', 'enum': ['USD', 'EUR', 'CAD', 'SGD']},
'dry_run': {'type': 'boolean'}, 'dry_run': {'type': 'boolean'},
'minimal_roi': { 'minimal_roi': {
'type': 'object', 'type': 'object',

View File

@ -15,6 +15,7 @@ from telegram.ext import CommandHandler, Updater
from freqtrade import exchange, __version__ from freqtrade import exchange, __version__
from freqtrade.misc import get_state, State, update_state from freqtrade.misc import get_state, State, update_state
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.fiat_convert import CryptoToFiatConverter
# Remove noisy log messages # Remove noisy log messages
logging.getLogger('requests.packages.urllib3').setLevel(logging.INFO) logging.getLogger('requests.packages.urllib3').setLevel(logging.INFO)
@ -23,6 +24,7 @@ logger = logging.getLogger(__name__)
_UPDATER: Updater = None _UPDATER: Updater = None
_CONF = {} _CONF = {}
_FIAT_CONVERT = CryptoToFiatConverter()
def init(config: dict) -> None: def init(config: dict) -> None:
@ -242,8 +244,28 @@ def _daily(bot: Bot, update: Update) -> None:
curdayprofit = sum(trade.calc_profit() for trade in trades) curdayprofit = sum(trade.calc_profit() for trade in trades)
profit_days[date.fromordinal(today - day)] = format(curdayprofit, '.8f') profit_days[date.fromordinal(today - day)] = format(curdayprofit, '.8f')
stats = [[key, str(value) + ' BTC'] for key, value in profit_days.items()] stats = [
stats = tabulate(stats, headers=['Day', 'Profit'], tablefmt='simple') [
key,
'{value:.8f} {symbol}'.format(value=float(value), symbol=_CONF['stake_currency']),
'{value:.3f} {symbol}'.format(
value=_FIAT_CONVERT.convert_amount(
value,
_CONF['stake_currency'],
_CONF['fiat_display_currency']
),
symbol=_CONF['fiat_display_currency']
)
]
for key, value in profit_days.items()
]
stats = tabulate(stats,
headers=[
'Day',
'Profit {}'.format(_CONF['stake_currency']),
'Profit {}'.format(_CONF['fiat_display_currency'])
],
tablefmt='simple')
message = '<b>Daily Profit over the last {} days</b>:\n<pre>{}</pre>'.format(timescale, stats) message = '<b>Daily Profit over the last {} days</b>:\n<pre>{}</pre>'.format(timescale, stats)
send_msg(message, bot=bot, parse_mode=ParseMode.HTML) send_msg(message, bot=bot, parse_mode=ParseMode.HTML)
@ -260,9 +282,9 @@ def _profit(bot: Bot, update: Update) -> None:
""" """
trades = Trade.query.order_by(Trade.id).all() trades = Trade.query.order_by(Trade.id).all()
profit_all_btc = [] profit_all_coin = []
profit_all_percent = [] profit_all_percent = []
profit_btc_closed = [] profit_closed_coin = []
profit_closed_percent = [] profit_closed_percent = []
durations = [] durations = []
@ -276,14 +298,14 @@ def _profit(bot: Bot, update: Update) -> None:
if not trade.is_open: if not trade.is_open:
profit_percent = trade.calc_profit_percent() profit_percent = trade.calc_profit_percent()
profit_btc_closed.append(trade.calc_profit()) profit_closed_coin.append(trade.calc_profit())
profit_closed_percent.append(profit_percent) profit_closed_percent.append(profit_percent)
else: else:
# Get current rate # Get current rate
current_rate = exchange.get_ticker(trade.pair)['bid'] current_rate = exchange.get_ticker(trade.pair)['bid']
profit_percent = trade.calc_profit_percent(rate=current_rate) profit_percent = trade.calc_profit_percent(rate=current_rate)
profit_all_btc.append(trade.calc_profit(rate=Decimal(trade.close_rate or current_rate))) profit_all_coin.append(trade.calc_profit(rate=Decimal(trade.close_rate or current_rate)))
profit_all_percent.append(profit_percent) profit_all_percent.append(profit_percent)
best_pair = Trade.session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \ best_pair = Trade.session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \
@ -297,19 +319,46 @@ def _profit(bot: Bot, update: Update) -> None:
return return
bp_pair, bp_rate = best_pair bp_pair, bp_rate = best_pair
# Prepare data to display
profit_closed_coin = round(sum(profit_closed_coin), 8)
profit_closed_percent = round(sum(profit_closed_percent) * 100, 2)
profit_closed_fiat = _FIAT_CONVERT.convert_amount(
profit_closed_coin,
_CONF['stake_currency'],
_CONF['fiat_display_currency']
)
profit_all_coin = round(sum(profit_all_coin), 8)
profit_all_percent = round(sum(profit_all_percent) * 100, 2)
profit_all_fiat = _FIAT_CONVERT.convert_amount(
profit_all_coin,
_CONF['stake_currency'],
_CONF['fiat_display_currency']
)
# Message to display
markdown_msg = """ markdown_msg = """
*ROI Trade closed:* `{profit_closed_btc:.8f} BTC ({profit_closed_percent:.2f}%)` *ROI:* Close trades
*ROI All trades:* `{profit_all_btc:.8f} BTC ({profit_all_percent:.2f}%)` `{profit_closed_coin:.8f} {coin} ({profit_closed_percent:.2f}%)`
`{profit_closed_fiat:.3f} {fiat}`
*ROI:* All trades
`{profit_all_coin:.8f} {coin} ({profit_all_percent:.2f}%)`
`{profit_all_fiat:.3f} {fiat}`
*Total Trade Count:* `{trade_count}` *Total Trade Count:* `{trade_count}`
*First Trade opened:* `{first_trade_date}` *First Trade opened:* `{first_trade_date}`
*Latest Trade opened:* `{latest_trade_date}` *Latest Trade opened:* `{latest_trade_date}`
*Avg. Duration:* `{avg_duration}` *Avg. Duration:* `{avg_duration}`
*Best Performing:* `{best_pair}: {best_rate:.2f}%` *Best Performing:* `{best_pair}: {best_rate:.2f}%`
""".format( """.format(
profit_closed_btc=round(sum(profit_btc_closed), 8), coin=_CONF['stake_currency'],
profit_closed_percent=round(sum(profit_closed_percent) * 100, 2), fiat=_CONF['fiat_display_currency'],
profit_all_btc=round(sum(profit_all_btc), 8), profit_closed_coin=profit_closed_coin,
profit_all_percent=round(sum(profit_all_percent) * 100, 2), profit_closed_percent=profit_closed_percent,
profit_closed_fiat=profit_closed_fiat,
profit_all_coin=profit_all_coin,
profit_all_percent=profit_all_percent,
profit_all_fiat=profit_all_fiat,
trade_count=len(trades), trade_count=len(trades),
first_trade_date=arrow.get(trades[0].open_date).humanize(), first_trade_date=arrow.get(trades[0].open_date).humanize(),
latest_trade_date=arrow.get(trades[-1].open_date).humanize(), latest_trade_date=arrow.get(trades[-1].open_date).humanize(),

View File

@ -16,6 +16,7 @@ def default_conf():
"max_open_trades": 1, "max_open_trades": 1,
"stake_currency": "BTC", "stake_currency": "BTC",
"stake_amount": 0.001, "stake_amount": 0.001,
"fiat_display_currency": "USD",
"dry_run": True, "dry_run": True,
"minimal_roi": { "minimal_roi": {
"40": 0.0, "40": 0.0,

View File

@ -0,0 +1,111 @@
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
import time
import pytest
from unittest.mock import MagicMock
from freqtrade.fiat_convert import CryptoToFiatConverter, CryptoFiat
def test_pair_convertion_object():
pair_convertion = CryptoFiat(
crypto_symbol='btc',
fiat_symbol='usd',
price=12345.0
)
# Check the cache duration is 6 hours
assert pair_convertion.CACHE_DURATION == 6 * 60 * 60
# Check a regular usage
assert pair_convertion.crypto_symbol == 'BTC'
assert pair_convertion.fiat_symbol == 'USD'
assert pair_convertion.price == 12345.0
assert pair_convertion.is_expired() is False
# Update the expiration time (- 2 hours) and check the behavior
pair_convertion._expiration = time.time() - 2 * 60 * 60
assert pair_convertion.is_expired() is True
# Check set price behaviour
time_reference = time.time() + pair_convertion.CACHE_DURATION
pair_convertion.set_price(price=30000.123)
assert pair_convertion.is_expired() is False
assert pair_convertion._expiration >= time_reference
assert pair_convertion.price == 30000.123
def test_fiat_convert_is_supported():
fiat_convert = CryptoToFiatConverter()
assert fiat_convert._is_supported_fiat(fiat='USD') is True
assert fiat_convert._is_supported_fiat(fiat='usd') is True
assert fiat_convert._is_supported_fiat(fiat='abc') is False
assert fiat_convert._is_supported_fiat(fiat='ABC') is False
def test_fiat_convert_add_pair():
fiat_convert = CryptoToFiatConverter()
assert len(fiat_convert._pairs) == 0
fiat_convert._add_pair(crypto_symbol='btc', fiat_symbol='usd', price=12345.0)
assert len(fiat_convert._pairs) == 1
assert fiat_convert._pairs[0].crypto_symbol == 'BTC'
assert fiat_convert._pairs[0].fiat_symbol == 'USD'
assert fiat_convert._pairs[0].price == 12345.0
fiat_convert._add_pair(crypto_symbol='btc', fiat_symbol='Eur', price=13000.2)
assert len(fiat_convert._pairs) == 2
assert fiat_convert._pairs[1].crypto_symbol == 'BTC'
assert fiat_convert._pairs[1].fiat_symbol == 'EUR'
assert fiat_convert._pairs[1].price == 13000.2
def test_fiat_convert_find_price(mocker):
api_mock = MagicMock(return_value={
'price_usd': 12345.0,
'price_eur': 13000.2
})
mocker.patch('freqtrade.fiat_convert.Pymarketcap.ticker', api_mock)
fiat_convert = CryptoToFiatConverter()
with pytest.raises(ValueError, match=r'The fiat ABC is not supported.'):
fiat_convert._find_price(crypto_symbol='BTC', fiat_symbol='ABC')
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 12345.0
assert fiat_convert.get_price(crypto_symbol='btc', fiat_symbol='usd') == 12345.0
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='EUR') == 13000.2
def test_fiat_convert_get_price(mocker):
api_mock = MagicMock(return_value={
'price_usd': 28000.0,
'price_eur': 15000.0
})
mocker.patch('freqtrade.fiat_convert.Pymarketcap.ticker', api_mock)
fiat_convert = CryptoToFiatConverter()
with pytest.raises(ValueError, match=r'The fiat US DOLLAR is not supported.'):
fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='US Dollar')
# Check the value return by the method
assert len(fiat_convert._pairs) == 0
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 28000.0
assert fiat_convert._pairs[0].crypto_symbol == 'BTC'
assert fiat_convert._pairs[0].fiat_symbol == 'USD'
assert fiat_convert._pairs[0].price == 28000.0
assert fiat_convert._pairs[0]._expiration is not 0
assert len(fiat_convert._pairs) == 1
# Verify the cached is used
fiat_convert._pairs[0].price = 9867.543
expiration = fiat_convert._pairs[0]._expiration
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 9867.543
assert fiat_convert._pairs[0]._expiration == expiration
# Verify the cache expiration
expiration = time.time() - 2 * 60 * 60
fiat_convert._pairs[0]._expiration = expiration
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 28000.0
assert fiat_convert._pairs[0]._expiration is not expiration

View File

@ -192,6 +192,9 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker):
}), }),
buy=MagicMock(return_value='mocked_limit_buy'), buy=MagicMock(return_value='mocked_limit_buy'),
sell=MagicMock(return_value='mocked_limit_sell')) sell=MagicMock(return_value='mocked_limit_sell'))
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
ticker=MagicMock(return_value={'price_usd': 15000.0}),
_cache_symbols=MagicMock(return_value={'BTC': 1}))
init(default_conf, create_engine('sqlite://')) init(default_conf, create_engine('sqlite://'))
create_trade(0.001) create_trade(0.001)

View File

@ -164,6 +164,9 @@ def test_profit_handle(
mocker.patch.multiple('freqtrade.main.exchange', mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(), validate_pairs=MagicMock(),
get_ticker=ticker) get_ticker=ticker)
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
ticker=MagicMock(return_value={'price_usd': 15000.0}),
_cache_symbols=MagicMock(return_value={'BTC': 1}))
init(default_conf, create_engine('sqlite://')) init(default_conf, create_engine('sqlite://'))
_profit(bot=MagicMock(), update=update) _profit(bot=MagicMock(), update=update)
@ -194,9 +197,14 @@ def test_profit_handle(
_profit(bot=MagicMock(), update=update) _profit(bot=MagicMock(), update=update)
assert msg_mock.call_count == 1 assert msg_mock.call_count == 1
assert '*ROI Trade closed:* `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0] assert '*ROI:* Close trades' in msg_mock.call_args_list[-1][0][0]
assert '*ROI All trades:* `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0] assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
assert 'Best Performing:* `BTC_ETH: 6.20%`' in msg_mock.call_args_list[-1][0][0] assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0]
assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
assert '*Best Performing:* `BTC_ETH: 6.20%`' in msg_mock.call_args_list[-1][0][0]
def test_forcesell_handle(default_conf, update, ticker, ticker_sell_up, mocker): def test_forcesell_handle(default_conf, update, ticker, ticker_sell_up, mocker):
@ -210,6 +218,9 @@ def test_forcesell_handle(default_conf, update, ticker, ticker_sell_up, mocker):
mocker.patch.multiple('freqtrade.main.exchange', mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(), validate_pairs=MagicMock(),
get_ticker=ticker) get_ticker=ticker)
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
ticker=MagicMock(return_value={'price_usd': 15000.0}),
_cache_symbols=MagicMock(return_value={'BTC': 1}))
init(default_conf, create_engine('sqlite://')) init(default_conf, create_engine('sqlite://'))
# Create some test data # Create some test data
@ -228,7 +239,9 @@ def test_forcesell_handle(default_conf, update, ticker, ticker_sell_up, mocker):
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0]
assert '0.00001172 (profit: ~6.11%, 0.00006126)' in rpc_mock.call_args_list[-1][0][0] assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
assert 'profit: ~6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0]
assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0]
def test_forcesell_down_handle(default_conf, update, ticker, ticker_sell_down, mocker): def test_forcesell_down_handle(default_conf, update, ticker, ticker_sell_down, mocker):
@ -242,6 +255,9 @@ def test_forcesell_down_handle(default_conf, update, ticker, ticker_sell_down, m
mocker.patch.multiple('freqtrade.main.exchange', mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(), validate_pairs=MagicMock(),
get_ticker=ticker) get_ticker=ticker)
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
ticker=MagicMock(return_value={'price_usd': 15000.0}),
_cache_symbols=MagicMock(return_value={'BTC': 1}))
init(default_conf, create_engine('sqlite://')) init(default_conf, create_engine('sqlite://'))
# Create some test data # Create some test data
@ -260,7 +276,9 @@ def test_forcesell_down_handle(default_conf, update, ticker, ticker_sell_down, m
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0]
assert '0.00001044 (profit: ~-5.48%, -0.00005492)' in rpc_mock.call_args_list[-1][0][0] assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
assert 'profit: ~-5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0]
def test_exec_forcesell_open_orders(default_conf, ticker, mocker): def test_exec_forcesell_open_orders(default_conf, ticker, mocker):
@ -298,6 +316,9 @@ def test_forcesell_all_handle(default_conf, update, ticker, mocker):
mocker.patch.multiple('freqtrade.main.exchange', mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(), validate_pairs=MagicMock(),
get_ticker=ticker) get_ticker=ticker)
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
ticker=MagicMock(return_value={'price_usd': 15000.0}),
_cache_symbols=MagicMock(return_value={'BTC': 1}))
init(default_conf, create_engine('sqlite://')) init(default_conf, create_engine('sqlite://'))
# Create some test data # Create some test data
@ -310,7 +331,9 @@ def test_forcesell_all_handle(default_conf, update, ticker, mocker):
assert rpc_mock.call_count == 4 assert rpc_mock.call_count == 4
for args in rpc_mock.call_args_list: for args in rpc_mock.call_args_list:
assert '0.00001098 (profit: ~-0.59%, -0.00000591)' in args[0][0] assert '0.00001098' in args[0][0]
assert 'profit: ~-0.59%, -0.00000591 BTC' in args[0][0]
assert '-0.089 USD' in args[0][0]
def test_forcesell_handle_invalid(default_conf, update, mocker): def test_forcesell_handle_invalid(default_conf, update, mocker):
@ -397,6 +420,9 @@ def test_daily_handle(
mocker.patch.multiple('freqtrade.main.exchange', mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(), validate_pairs=MagicMock(),
get_ticker=ticker) get_ticker=ticker)
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
ticker=MagicMock(return_value={'price_usd': 15000.0}),
_cache_symbols=MagicMock(return_value={'BTC': 1}))
init(default_conf, create_engine('sqlite://')) init(default_conf, create_engine('sqlite://'))
# Create some test data # Create some test data
@ -418,7 +444,9 @@ def test_daily_handle(
_daily(bot=MagicMock(), update=update) _daily(bot=MagicMock(), update=update)
assert msg_mock.call_count == 1 assert msg_mock.call_count == 1
assert 'Daily' in msg_mock.call_args_list[0][0][0] assert 'Daily' in msg_mock.call_args_list[0][0][0]
assert str(datetime.utcnow().date()) + ' 0.00006217 BTC' in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
# Try invalid data # Try invalid data
msg_mock.reset_mock() msg_mock.reset_mock()

View File

@ -19,6 +19,7 @@ hyperopt==0.1
# do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325 # do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325
networkx==1.11 networkx==1.11
tabulate==0.8.2 tabulate==0.8.2
pymarketcap==3.3.139
# Required for plotting data # Required for plotting data
#matplotlib==2.1.0 #matplotlib==2.1.0

View File

@ -35,6 +35,7 @@ setup(name='freqtrade',
'TA-Lib', 'TA-Lib',
'tabulate', 'tabulate',
'cachetools', 'cachetools',
'pymarketcap',
], ],
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,