Merge pull request #2729 from hroff-1902/minor-freqtrade-3
Cosmetics in freqtradebot
This commit is contained in:
commit
cac0e37b06
@ -27,6 +27,7 @@ from freqtrade.state import State
|
|||||||
from freqtrade.strategy.interface import IStrategy, SellType
|
from freqtrade.strategy.interface import IStrategy, SellType
|
||||||
from freqtrade.wallets import Wallets
|
from freqtrade.wallets import Wallets
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -181,6 +182,43 @@ class FreqtradeBot:
|
|||||||
open_trades = len(Trade.get_open_trades())
|
open_trades = len(Trade.get_open_trades())
|
||||||
return max(0, self.config['max_open_trades'] - open_trades)
|
return max(0, self.config['max_open_trades'] - open_trades)
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUY / enter positions / open trades logic and methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def enter_positions(self) -> int:
|
||||||
|
"""
|
||||||
|
Tries to execute buy orders for new trades (positions)
|
||||||
|
"""
|
||||||
|
trades_created = 0
|
||||||
|
|
||||||
|
whitelist = copy.deepcopy(self.active_pair_whitelist)
|
||||||
|
if not whitelist:
|
||||||
|
logger.info("Active pair whitelist is empty.")
|
||||||
|
else:
|
||||||
|
# Remove pairs for currently opened trades from the whitelist
|
||||||
|
for trade in Trade.get_open_trades():
|
||||||
|
if trade.pair in whitelist:
|
||||||
|
whitelist.remove(trade.pair)
|
||||||
|
logger.debug('Ignoring %s in pair whitelist', trade.pair)
|
||||||
|
|
||||||
|
if not whitelist:
|
||||||
|
logger.info("No currency pair in active pair whitelist, "
|
||||||
|
"but checking to sell open trades.")
|
||||||
|
else:
|
||||||
|
# Create entity and execute trade for each pair from whitelist
|
||||||
|
for pair in whitelist:
|
||||||
|
try:
|
||||||
|
trades_created += self.create_trade(pair)
|
||||||
|
except DependencyException as exception:
|
||||||
|
logger.warning('Unable to create trade for %s: %s', pair, exception)
|
||||||
|
|
||||||
|
if not trades_created:
|
||||||
|
logger.debug("Found no buy signals for whitelisted currencies. "
|
||||||
|
"Trying again...")
|
||||||
|
|
||||||
|
return trades_created
|
||||||
|
|
||||||
def get_target_bid(self, pair: str, tick: Dict = None) -> float:
|
def get_target_bid(self, pair: str, tick: Dict = None) -> float:
|
||||||
"""
|
"""
|
||||||
Calculates bid target between current ask price and last price
|
Calculates bid target between current ask price and last price
|
||||||
@ -369,7 +407,7 @@ class FreqtradeBot:
|
|||||||
if price:
|
if price:
|
||||||
buy_limit_requested = price
|
buy_limit_requested = price
|
||||||
else:
|
else:
|
||||||
# Calculate amount
|
# Calculate price
|
||||||
buy_limit_requested = self.get_target_bid(pair)
|
buy_limit_requested = self.get_target_bid(pair)
|
||||||
|
|
||||||
min_stake_amount = self._get_min_pair_stake_amount(pair, buy_limit_requested)
|
min_stake_amount = self._get_min_pair_stake_amount(pair, buy_limit_requested)
|
||||||
@ -460,38 +498,9 @@ class FreqtradeBot:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def enter_positions(self) -> int:
|
#
|
||||||
"""
|
# SELL / exit positions / close trades logic and methods
|
||||||
Tries to execute buy orders for new trades (positions)
|
#
|
||||||
"""
|
|
||||||
trades_created = 0
|
|
||||||
|
|
||||||
whitelist = copy.deepcopy(self.active_pair_whitelist)
|
|
||||||
if not whitelist:
|
|
||||||
logger.info("Active pair whitelist is empty.")
|
|
||||||
else:
|
|
||||||
# Remove pairs for currently opened trades from the whitelist
|
|
||||||
for trade in Trade.get_open_trades():
|
|
||||||
if trade.pair in whitelist:
|
|
||||||
whitelist.remove(trade.pair)
|
|
||||||
logger.debug('Ignoring %s in pair whitelist', trade.pair)
|
|
||||||
|
|
||||||
if not whitelist:
|
|
||||||
logger.info("No currency pair in active pair whitelist, "
|
|
||||||
"but checking to sell open trades.")
|
|
||||||
else:
|
|
||||||
# Create entity and execute trade for each pair from whitelist
|
|
||||||
for pair in whitelist:
|
|
||||||
try:
|
|
||||||
trades_created += self.create_trade(pair)
|
|
||||||
except DependencyException as exception:
|
|
||||||
logger.warning('Unable to create trade for %s: %s', pair, exception)
|
|
||||||
|
|
||||||
if not trades_created:
|
|
||||||
logger.debug("Found no buy signals for whitelisted currencies. "
|
|
||||||
"Trying again...")
|
|
||||||
|
|
||||||
return trades_created
|
|
||||||
|
|
||||||
def exit_positions(self, trades: List[Any]) -> int:
|
def exit_positions(self, trades: List[Any]) -> int:
|
||||||
"""
|
"""
|
||||||
@ -519,87 +528,6 @@ class FreqtradeBot:
|
|||||||
|
|
||||||
return trades_closed
|
return trades_closed
|
||||||
|
|
||||||
def get_real_amount(self, trade: Trade, order: Dict, order_amount: float = None) -> float:
|
|
||||||
"""
|
|
||||||
Get real amount for the trade
|
|
||||||
Necessary for exchanges which charge fees in base currency (e.g. binance)
|
|
||||||
"""
|
|
||||||
if order_amount is None:
|
|
||||||
order_amount = order['amount']
|
|
||||||
# Only run for closed orders
|
|
||||||
if trade.fee_open == 0 or order['status'] == 'open':
|
|
||||||
return order_amount
|
|
||||||
|
|
||||||
# use fee from order-dict if possible
|
|
||||||
if ('fee' in order and order['fee'] is not None and
|
|
||||||
(order['fee'].keys() >= {'currency', 'cost'})):
|
|
||||||
if (order['fee']['currency'] is not None and
|
|
||||||
order['fee']['cost'] is not None and
|
|
||||||
trade.pair.startswith(order['fee']['currency'])):
|
|
||||||
new_amount = order_amount - order['fee']['cost']
|
|
||||||
logger.info("Applying fee on amount for %s (from %s to %s) from Order",
|
|
||||||
trade, order['amount'], new_amount)
|
|
||||||
return new_amount
|
|
||||||
|
|
||||||
# Fallback to Trades
|
|
||||||
trades = self.exchange.get_trades_for_order(trade.open_order_id, trade.pair,
|
|
||||||
trade.open_date)
|
|
||||||
|
|
||||||
if len(trades) == 0:
|
|
||||||
logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade)
|
|
||||||
return order_amount
|
|
||||||
amount = 0
|
|
||||||
fee_abs = 0
|
|
||||||
for exectrade in trades:
|
|
||||||
amount += exectrade['amount']
|
|
||||||
if ("fee" in exectrade and exectrade['fee'] is not None and
|
|
||||||
(exectrade['fee'].keys() >= {'currency', 'cost'})):
|
|
||||||
# only applies if fee is in quote currency!
|
|
||||||
if (exectrade['fee']['currency'] is not None and
|
|
||||||
exectrade['fee']['cost'] is not None and
|
|
||||||
trade.pair.startswith(exectrade['fee']['currency'])):
|
|
||||||
fee_abs += exectrade['fee']['cost']
|
|
||||||
|
|
||||||
if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC):
|
|
||||||
logger.warning(f"Amount {amount} does not match amount {trade.amount}")
|
|
||||||
raise DependencyException("Half bought? Amounts don't match")
|
|
||||||
real_amount = amount - fee_abs
|
|
||||||
if fee_abs != 0:
|
|
||||||
logger.info(f"Applying fee on amount for {trade} "
|
|
||||||
f"(from {order_amount} to {real_amount}) from Trades")
|
|
||||||
return real_amount
|
|
||||||
|
|
||||||
def update_trade_state(self, trade, action_order: dict = None):
|
|
||||||
"""
|
|
||||||
Checks trades with open orders and updates the amount if necessary
|
|
||||||
"""
|
|
||||||
# Get order details for actual price per unit
|
|
||||||
if trade.open_order_id:
|
|
||||||
# Update trade with order values
|
|
||||||
logger.info('Found open order for %s', trade)
|
|
||||||
try:
|
|
||||||
order = action_order or self.exchange.get_order(trade.open_order_id, trade.pair)
|
|
||||||
except InvalidOrderException as exception:
|
|
||||||
logger.warning('Unable to fetch order %s: %s', trade.open_order_id, exception)
|
|
||||||
return
|
|
||||||
# Try update amount (binance-fix)
|
|
||||||
try:
|
|
||||||
new_amount = self.get_real_amount(trade, order)
|
|
||||||
if not isclose(order['amount'], new_amount, abs_tol=constants.MATH_CLOSE_PREC):
|
|
||||||
order['amount'] = new_amount
|
|
||||||
# Fee was applied, so set to 0
|
|
||||||
trade.fee_open = 0
|
|
||||||
trade.recalc_open_trade_price()
|
|
||||||
|
|
||||||
except DependencyException as exception:
|
|
||||||
logger.warning("Could not update trade amount: %s", exception)
|
|
||||||
|
|
||||||
trade.update(order)
|
|
||||||
|
|
||||||
# Updating wallets when order is closed
|
|
||||||
if not trade.is_open:
|
|
||||||
self.wallets.update()
|
|
||||||
|
|
||||||
def get_sell_rate(self, pair: str, refresh: bool) -> float:
|
def get_sell_rate(self, pair: str, refresh: bool) -> float:
|
||||||
"""
|
"""
|
||||||
Get sell rate - either using get-ticker bid or first bid based on orderbook
|
Get sell rate - either using get-ticker bid or first bid based on orderbook
|
||||||
@ -1038,3 +966,88 @@ class FreqtradeBot:
|
|||||||
|
|
||||||
# Send the message
|
# Send the message
|
||||||
self.rpc.send_msg(msg)
|
self.rpc.send_msg(msg)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Common update trade state methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def update_trade_state(self, trade, action_order: dict = None):
|
||||||
|
"""
|
||||||
|
Checks trades with open orders and updates the amount if necessary
|
||||||
|
"""
|
||||||
|
# Get order details for actual price per unit
|
||||||
|
if trade.open_order_id:
|
||||||
|
# Update trade with order values
|
||||||
|
logger.info('Found open order for %s', trade)
|
||||||
|
try:
|
||||||
|
order = action_order or self.exchange.get_order(trade.open_order_id, trade.pair)
|
||||||
|
except InvalidOrderException as exception:
|
||||||
|
logger.warning('Unable to fetch order %s: %s', trade.open_order_id, exception)
|
||||||
|
return
|
||||||
|
# Try update amount (binance-fix)
|
||||||
|
try:
|
||||||
|
new_amount = self.get_real_amount(trade, order)
|
||||||
|
if not isclose(order['amount'], new_amount, abs_tol=constants.MATH_CLOSE_PREC):
|
||||||
|
order['amount'] = new_amount
|
||||||
|
# Fee was applied, so set to 0
|
||||||
|
trade.fee_open = 0
|
||||||
|
trade.recalc_open_trade_price()
|
||||||
|
|
||||||
|
except DependencyException as exception:
|
||||||
|
logger.warning("Could not update trade amount: %s", exception)
|
||||||
|
|
||||||
|
trade.update(order)
|
||||||
|
|
||||||
|
# Updating wallets when order is closed
|
||||||
|
if not trade.is_open:
|
||||||
|
self.wallets.update()
|
||||||
|
|
||||||
|
def get_real_amount(self, trade: Trade, order: Dict, order_amount: float = None) -> float:
|
||||||
|
"""
|
||||||
|
Get real amount for the trade
|
||||||
|
Necessary for exchanges which charge fees in base currency (e.g. binance)
|
||||||
|
"""
|
||||||
|
if order_amount is None:
|
||||||
|
order_amount = order['amount']
|
||||||
|
# Only run for closed orders
|
||||||
|
if trade.fee_open == 0 or order['status'] == 'open':
|
||||||
|
return order_amount
|
||||||
|
|
||||||
|
# use fee from order-dict if possible
|
||||||
|
if ('fee' in order and order['fee'] is not None and
|
||||||
|
(order['fee'].keys() >= {'currency', 'cost'})):
|
||||||
|
if (order['fee']['currency'] is not None and
|
||||||
|
order['fee']['cost'] is not None and
|
||||||
|
trade.pair.startswith(order['fee']['currency'])):
|
||||||
|
new_amount = order_amount - order['fee']['cost']
|
||||||
|
logger.info("Applying fee on amount for %s (from %s to %s) from Order",
|
||||||
|
trade, order['amount'], new_amount)
|
||||||
|
return new_amount
|
||||||
|
|
||||||
|
# Fallback to Trades
|
||||||
|
trades = self.exchange.get_trades_for_order(trade.open_order_id, trade.pair,
|
||||||
|
trade.open_date)
|
||||||
|
|
||||||
|
if len(trades) == 0:
|
||||||
|
logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade)
|
||||||
|
return order_amount
|
||||||
|
amount = 0
|
||||||
|
fee_abs = 0
|
||||||
|
for exectrade in trades:
|
||||||
|
amount += exectrade['amount']
|
||||||
|
if ("fee" in exectrade and exectrade['fee'] is not None and
|
||||||
|
(exectrade['fee'].keys() >= {'currency', 'cost'})):
|
||||||
|
# only applies if fee is in quote currency!
|
||||||
|
if (exectrade['fee']['currency'] is not None and
|
||||||
|
exectrade['fee']['cost'] is not None and
|
||||||
|
trade.pair.startswith(exectrade['fee']['currency'])):
|
||||||
|
fee_abs += exectrade['fee']['cost']
|
||||||
|
|
||||||
|
if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC):
|
||||||
|
logger.warning(f"Amount {amount} does not match amount {trade.amount}")
|
||||||
|
raise DependencyException("Half bought? Amounts don't match")
|
||||||
|
real_amount = amount - fee_abs
|
||||||
|
if fee_abs != 0:
|
||||||
|
logger.info(f"Applying fee on amount for {trade} "
|
||||||
|
f"(from {order_amount} to {real_amount}) from Trades")
|
||||||
|
return real_amount
|
||||||
|
Loading…
Reference in New Issue
Block a user