Merge pull request #563 from gcarq/feature/typehints
Set correct typehints and minor code cleanups
This commit is contained in:
commit
04c6474dd0
@ -3,13 +3,15 @@ Functions to analyze ticker data with indicators and produce buy and sell signal
|
||||
"""
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
from typing import Dict, List
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
import arrow
|
||||
from pandas import DataFrame, to_datetime
|
||||
|
||||
from freqtrade.exchange import get_ticker_history
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade.strategy.strategy import Strategy
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.strategy import Strategy
|
||||
|
||||
|
||||
class SignalType(Enum):
|
||||
@ -96,9 +98,7 @@ class Analyze(object):
|
||||
dataframe = self.populate_sell_trend(dataframe)
|
||||
return dataframe
|
||||
|
||||
# FIX: Maybe return False, if an error has occured,
|
||||
# Otherwise we might mask an error as an non-signal-scenario
|
||||
def get_signal(self, pair: str, interval: int) -> (bool, bool):
|
||||
def get_signal(self, pair: str, interval: int) -> Tuple[bool, bool]:
|
||||
"""
|
||||
Calculates current signal based several technical analysis indicators
|
||||
:param pair: pair in format BTC_ANT or BTC-ANT
|
||||
@ -108,7 +108,7 @@ class Analyze(object):
|
||||
ticker_hist = get_ticker_history(pair, interval)
|
||||
if not ticker_hist:
|
||||
self.logger.warning('Empty ticker history for pair %s', pair)
|
||||
return (False, False) # return False ?
|
||||
return False, False
|
||||
|
||||
try:
|
||||
dataframe = self.analyze_ticker(ticker_hist)
|
||||
@ -118,18 +118,18 @@ class Analyze(object):
|
||||
pair,
|
||||
str(error)
|
||||
)
|
||||
return (False, False) # return False ?
|
||||
return False, False
|
||||
except Exception as error:
|
||||
self.logger.exception(
|
||||
'Unexpected error when analyzing ticker for pair %s: %s',
|
||||
pair,
|
||||
str(error)
|
||||
)
|
||||
return (False, False) # return False ?
|
||||
return False, False
|
||||
|
||||
if dataframe.empty:
|
||||
self.logger.warning('Empty dataframe for pair %s', pair)
|
||||
return (False, False) # return False ?
|
||||
return False, False
|
||||
|
||||
latest = dataframe.iloc[-1]
|
||||
|
||||
@ -141,7 +141,7 @@ class Analyze(object):
|
||||
pair,
|
||||
(arrow.utcnow() - signal_date).seconds // 60
|
||||
)
|
||||
return (False, False) # return False ?
|
||||
return False, False
|
||||
|
||||
(buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1
|
||||
self.logger.debug(
|
||||
@ -151,7 +151,7 @@ class Analyze(object):
|
||||
str(buy),
|
||||
str(sell)
|
||||
)
|
||||
return (buy, sell)
|
||||
return buy, sell
|
||||
|
||||
def should_sell(self, trade: Trade, rate: float, date: datetime, buy: bool, sell: bool) -> bool:
|
||||
"""
|
||||
|
@ -3,10 +3,10 @@ This module contains the argument manager class
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
from typing import List
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
from freqtrade import __version__
|
||||
from freqtrade.constants import Constants
|
||||
@ -22,11 +22,11 @@ class Arguments(object):
|
||||
self.parsed_arg = None
|
||||
self.parser = argparse.ArgumentParser(description=description)
|
||||
|
||||
def _load_args(self):
|
||||
def _load_args(self) -> None:
|
||||
self.common_args_parser()
|
||||
self._build_subcommands()
|
||||
|
||||
def get_parsed_arg(self) -> List[str]:
|
||||
def get_parsed_arg(self) -> argparse.Namespace:
|
||||
"""
|
||||
Return the list of arguments
|
||||
:return: List[str] List of arguments
|
||||
@ -37,7 +37,7 @@ class Arguments(object):
|
||||
|
||||
return self.parsed_arg
|
||||
|
||||
def parse_args(self) -> List[str]:
|
||||
def parse_args(self) -> argparse.Namespace:
|
||||
"""
|
||||
Parses given arguments and returns an argparse Namespace instance.
|
||||
"""
|
||||
@ -205,7 +205,7 @@ class Arguments(object):
|
||||
self.hyperopt_options(hyperopt_cmd)
|
||||
|
||||
@staticmethod
|
||||
def parse_timerange(text: str) -> (List, int, int):
|
||||
def parse_timerange(text: str) -> Optional[Tuple[List, int, int]]:
|
||||
"""
|
||||
Parse the value of the argument --timerange to determine what is the range desired
|
||||
:param text: value from --timerange
|
||||
@ -236,10 +236,10 @@ class Arguments(object):
|
||||
stop = rvals[index]
|
||||
if stype[1] != 'date':
|
||||
stop = int(stop)
|
||||
return (stype, start, stop)
|
||||
return stype, start, stop
|
||||
raise Exception('Incorrect syntax for timerange "%s"' % text)
|
||||
|
||||
def scripts_options(self):
|
||||
def scripts_options(self) -> None:
|
||||
"""
|
||||
Parses given arguments for plot scripts.
|
||||
"""
|
||||
|
@ -3,8 +3,9 @@ This module contains the configuration class
|
||||
"""
|
||||
|
||||
import json
|
||||
from argparse import Namespace
|
||||
from typing import Dict, Any
|
||||
|
||||
from typing import Dict, List, Any
|
||||
from jsonschema import Draft4Validator, validate
|
||||
from jsonschema.exceptions import ValidationError, best_match
|
||||
|
||||
@ -17,7 +18,7 @@ class Configuration(object):
|
||||
Class to read and init the bot configuration
|
||||
Reuse this class for the bot, backtesting, hyperopt and every script that required configuration
|
||||
"""
|
||||
def __init__(self, args: List[str], do_not_init=False) -> None:
|
||||
def __init__(self, args: Namespace) -> None:
|
||||
self.args = args
|
||||
self.logging = Logger(name=__name__)
|
||||
self.logger = self.logging.get_logger()
|
||||
|
@ -1,8 +1,8 @@
|
||||
import logging
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from bittrex.bittrex import Bittrex as _Bittrex
|
||||
from bittrex.bittrex import API_V1_1, API_V2_0
|
||||
from bittrex.bittrex import Bittrex as _Bittrex
|
||||
from requests.exceptions import ContentDecodingError
|
||||
|
||||
from freqtrade import OperationalException
|
||||
|
@ -5,12 +5,13 @@ e.g BTC to USD
|
||||
|
||||
import logging
|
||||
import time
|
||||
|
||||
from coinmarketcap import Market
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CryptoFiat():
|
||||
class CryptoFiat(object):
|
||||
"""
|
||||
Object to describe what is the price of Crypto-currency in a FIAT
|
||||
"""
|
||||
|
@ -6,11 +6,14 @@ import copy
|
||||
import json
|
||||
import time
|
||||
import traceback
|
||||
from typing import Dict, List, Optional, Any, Callable
|
||||
from datetime import datetime
|
||||
import requests
|
||||
from typing import Dict, List, Optional, Any, Callable
|
||||
|
||||
import arrow
|
||||
import requests
|
||||
from cachetools import cached, TTLCache
|
||||
|
||||
from freqtrade import (DependencyException, OperationalException, exchange, persistence)
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.constants import Constants
|
||||
from freqtrade.fiat_convert import CryptoToFiatConverter
|
||||
@ -18,7 +21,6 @@ from freqtrade.logger import Logger
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc.rpc_manager import RPCManager
|
||||
from freqtrade.state import State
|
||||
from freqtrade import (DependencyException, OperationalException, exchange, persistence)
|
||||
|
||||
|
||||
class FreqtradeBot(object):
|
||||
@ -27,7 +29,7 @@ class FreqtradeBot(object):
|
||||
This is from here the bot start its logic.
|
||||
"""
|
||||
|
||||
def __init__(self, config: Dict[str, Any], db_url: Optional[str] = None) -> bool:
|
||||
def __init__(self, config: Dict[str, Any], db_url: Optional[str] = None):
|
||||
"""
|
||||
Init all variables and object the bot need to work
|
||||
:param config: configuration dict, you can use the Configuration.get_config()
|
||||
|
@ -1,19 +1,19 @@
|
||||
from math import exp, pi, sqrt, cos
|
||||
|
||||
import numpy
|
||||
import numpy as np
|
||||
import talib as ta
|
||||
from pandas import Series
|
||||
|
||||
|
||||
def went_up(series: Series) -> Series:
|
||||
def went_up(series: Series) -> bool:
|
||||
return series > series.shift(1)
|
||||
|
||||
|
||||
def went_down(series: Series) -> Series:
|
||||
def went_down(series: Series) -> bool:
|
||||
return series < series.shift(1)
|
||||
|
||||
|
||||
def ehlers_super_smoother(series: Series, smoothing: float = 6):
|
||||
def ehlers_super_smoother(series: Series, smoothing: float = 6) -> type(Series):
|
||||
magic = pi * sqrt(2) / smoothing
|
||||
a1 = exp(-magic)
|
||||
coeff2 = 2 * a1 * cos(magic)
|
||||
@ -29,7 +29,7 @@ def ehlers_super_smoother(series: Series, smoothing: float = 6):
|
||||
return filtered
|
||||
|
||||
|
||||
def fishers_inverse(series: Series, smoothing: float = 0):
|
||||
def fishers_inverse(series: Series, smoothing: float = 0) -> np.ndarray:
|
||||
""" Does a smoothed fishers inverse transformation.
|
||||
Can be used with any oscillator that goes from 0 to 100 like RSI or MFI """
|
||||
v1 = 0.1 * (series - 50)
|
||||
@ -37,4 +37,4 @@ def fishers_inverse(series: Series, smoothing: float = 0):
|
||||
v2 = ta.WMA(v1.values, timeperiod=smoothing)
|
||||
else:
|
||||
v2 = v1
|
||||
return (numpy.exp(2 * v2)-1) / (numpy.exp(2 * v2) + 1)
|
||||
return (np.exp(2 * v2)-1) / (np.exp(2 * v2) + 1)
|
||||
|
@ -6,17 +6,18 @@ Read the documentation to know what cli arguments you need.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from typing import Dict
|
||||
from freqtrade.configuration import Configuration
|
||||
from typing import List
|
||||
|
||||
from freqtrade import (__version__)
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade import (__version__)
|
||||
|
||||
logger = Logger(name='freqtrade').get_logger()
|
||||
|
||||
|
||||
def main(sysargv: Dict) -> None:
|
||||
def main(sysargv: List[str]) -> None:
|
||||
"""
|
||||
This function will initiate the bot and start the trading loop.
|
||||
:return: None
|
||||
|
@ -2,16 +2,19 @@
|
||||
Various tool function for Freqtrade and scripts
|
||||
"""
|
||||
|
||||
import re
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Dict
|
||||
|
||||
import numpy as np
|
||||
from pandas import DataFrame
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def shorten_date(_date):
|
||||
def shorten_date(_date: str) -> str:
|
||||
"""
|
||||
Trim the date so it fits on small screens
|
||||
"""
|
||||
@ -28,7 +31,7 @@ def shorten_date(_date):
|
||||
# Matplotlib doesn't support ::datetime64, #
|
||||
# so we need to convert it into ::datetime #
|
||||
############################################
|
||||
def datesarray_to_datetimearray(dates):
|
||||
def datesarray_to_datetimearray(dates: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
Convert an pandas-array of timestamps into
|
||||
An numpy-array of datetimes
|
||||
@ -42,10 +45,10 @@ def datesarray_to_datetimearray(dates):
|
||||
return np.array(times)
|
||||
|
||||
|
||||
def common_datearray(dfs):
|
||||
def common_datearray(dfs: Dict[str, DataFrame]) -> np.ndarray:
|
||||
"""
|
||||
Return dates from Dataframe
|
||||
:param dfs: Dataframe
|
||||
:param dfs: Dict with format pair: pair_data
|
||||
:return: List of dates
|
||||
"""
|
||||
alldates = {}
|
||||
|
@ -1,20 +1,20 @@
|
||||
# pragma pylint: disable=missing-docstring
|
||||
|
||||
import gzip
|
||||
import json
|
||||
import os
|
||||
from typing import Optional, List, Dict
|
||||
import gzip
|
||||
from freqtrade.exchange import get_ticker_history
|
||||
from typing import Optional, List, Dict, Tuple
|
||||
|
||||
from freqtrade import misc
|
||||
from freqtrade.exchange import get_ticker_history
|
||||
from freqtrade.logger import Logger
|
||||
from user_data.hyperopt_conf import hyperopt_optimize_conf
|
||||
|
||||
logger = Logger(name=__name__).get_logger()
|
||||
|
||||
|
||||
def trim_tickerlist(tickerlist, timerange):
|
||||
(stype, start, stop) = timerange
|
||||
def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) -> List[Dict]:
|
||||
stype, start, stop = timerange
|
||||
if stype == (None, 'line'):
|
||||
return tickerlist[stop:]
|
||||
elif stype == ('line', None):
|
||||
@ -25,7 +25,10 @@ def trim_tickerlist(tickerlist, timerange):
|
||||
return tickerlist
|
||||
|
||||
|
||||
def load_tickerdata_file(datadir, pair, ticker_interval, timerange=None):
|
||||
def load_tickerdata_file(
|
||||
datadir: str, pair: str,
|
||||
ticker_interval: int,
|
||||
timerange: Optional[Tuple[Tuple, int, int]] = None) -> Optional[List[Dict]]:
|
||||
"""
|
||||
Load a pair from file,
|
||||
:return dict OR empty if unsuccesful
|
||||
@ -55,12 +58,12 @@ def load_tickerdata_file(datadir, pair, ticker_interval, timerange=None):
|
||||
return pairdata
|
||||
|
||||
|
||||
def load_data(datadir: str, ticker_interval: int, pairs: Optional[List[str]] = None,
|
||||
refresh_pairs: Optional[bool] = False, timerange=None) -> Dict[str, List]:
|
||||
def load_data(datadir: str, ticker_interval: int,
|
||||
pairs: Optional[List[str]] = None,
|
||||
refresh_pairs: Optional[bool] = False,
|
||||
timerange: Optional[Tuple[Tuple, int, int]] = None) -> Dict[str, List]:
|
||||
"""
|
||||
Loads ticker history data for the given parameters
|
||||
:param ticker_interval: ticker interval in minutes
|
||||
:param pairs: list of pairs
|
||||
:return: dict
|
||||
"""
|
||||
result = {}
|
||||
|
@ -3,18 +3,19 @@
|
||||
"""
|
||||
This module contains the backtesting logic
|
||||
"""
|
||||
from argparse import Namespace
|
||||
from typing import Dict, Tuple, Any, List, Optional
|
||||
|
||||
from typing import Dict, Tuple, Any
|
||||
import arrow
|
||||
from pandas import DataFrame, Series
|
||||
from tabulate import tabulate
|
||||
|
||||
import freqtrade.optimize as optimize
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.exchange import Bittrex
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade import exchange
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade.exchange import Bittrex
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.persistence import Trade
|
||||
@ -101,7 +102,10 @@ class Backtesting(object):
|
||||
])
|
||||
return tabulate(tabular_data, headers=headers, floatfmt=floatfmt)
|
||||
|
||||
def _get_sell_trade_entry(self, pair, buy_row, partial_ticker, trade_count_lock, args):
|
||||
def _get_sell_trade_entry(
|
||||
self, pair: str, buy_row: DataFrame,
|
||||
partial_ticker: List, trade_count_lock: Dict, args: Dict) -> Optional[Tuple]:
|
||||
|
||||
stake_amount = args['stake_amount']
|
||||
max_open_trades = args.get('max_open_trades', 0)
|
||||
trade = Trade(
|
||||
@ -132,7 +136,7 @@ class Backtesting(object):
|
||||
sell_row.date
|
||||
return None
|
||||
|
||||
def backtest(self, args) -> DataFrame:
|
||||
def backtest(self, args: Dict) -> DataFrame:
|
||||
"""
|
||||
Implements backtesting functionality
|
||||
|
||||
@ -273,7 +277,7 @@ class Backtesting(object):
|
||||
)
|
||||
|
||||
|
||||
def setup_configuration(args) -> Dict[str, Any]:
|
||||
def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
||||
"""
|
||||
Prepare the configuration for the backtesting
|
||||
:param args: Cli args from Arguments()
|
||||
@ -289,7 +293,7 @@ def setup_configuration(args) -> Dict[str, Any]:
|
||||
return config
|
||||
|
||||
|
||||
def start(args) -> None:
|
||||
def start(args: Namespace) -> None:
|
||||
"""
|
||||
Start Backtesting script
|
||||
:param args: Cli args from Arguments()
|
||||
|
@ -10,6 +10,7 @@ import os
|
||||
import pickle
|
||||
import signal
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
from functools import reduce
|
||||
from math import exp
|
||||
from operator import itemgetter
|
||||
@ -22,11 +23,11 @@ from hyperopt.mongoexp import MongoTrials
|
||||
from pandas import DataFrame
|
||||
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade.optimize import load_data
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade.optimize import load_data
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from user_data.hyperopt_conf import hyperopt_optimize_conf
|
||||
|
||||
|
||||
@ -240,7 +241,7 @@ class Hyperopt(Backtesting):
|
||||
return trade_loss + profit_loss + duration_loss
|
||||
|
||||
@staticmethod
|
||||
def generate_roi_table(params) -> Dict[int, float]:
|
||||
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||
"""
|
||||
Generate the ROI table thqt will be used by Hyperopt
|
||||
"""
|
||||
@ -335,7 +336,7 @@ class Hyperopt(Backtesting):
|
||||
]),
|
||||
}
|
||||
|
||||
def has_space(self, space) -> bool:
|
||||
def has_space(self, space: str) -> bool:
|
||||
"""
|
||||
Tell if a space value is contained in the configuration
|
||||
"""
|
||||
@ -433,7 +434,7 @@ class Hyperopt(Backtesting):
|
||||
|
||||
return populate_buy_trend
|
||||
|
||||
def generate_optimizer(self, params) -> Dict:
|
||||
def generate_optimizer(self, params: Dict) -> Dict:
|
||||
if self.has_space('roi'):
|
||||
self.analyze.strategy.minimal_roi = self.generate_roi_table(params)
|
||||
|
||||
@ -496,7 +497,7 @@ class Hyperopt(Backtesting):
|
||||
results.duration.mean(),
|
||||
)
|
||||
|
||||
def start(self):
|
||||
def start(self) -> None:
|
||||
timerange = Arguments.parse_timerange(self.config.get('timerange'))
|
||||
data = load_data(
|
||||
datadir=self.config.get('datadir'),
|
||||
@ -571,7 +572,7 @@ class Hyperopt(Backtesting):
|
||||
# Store trials result to file to resume next time
|
||||
self.save_trials()
|
||||
|
||||
def signal_handler(self, sig, frame):
|
||||
def signal_handler(self, sig, frame) -> None:
|
||||
"""
|
||||
Hyperopt SIGINT handler
|
||||
"""
|
||||
@ -585,7 +586,7 @@ class Hyperopt(Backtesting):
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def start(args) -> None:
|
||||
def start(args: Namespace) -> None:
|
||||
"""
|
||||
Start Backtesting script
|
||||
:param args: Cli args from Arguments()
|
||||
|
@ -207,6 +207,7 @@ class Trade(_DECL_BASE):
|
||||
Calculates the profit in percentage (including fee).
|
||||
:param rate: rate to compare with (optional).
|
||||
If rate is not set self.close_rate will be used
|
||||
:param fee: fee to use on the close rate (optional).
|
||||
:return: profit in percentage as float
|
||||
"""
|
||||
getcontext().prec = 8
|
||||
|
@ -2,16 +2,19 @@
|
||||
This module contains class to define a RPC communications
|
||||
"""
|
||||
|
||||
from decimal import Decimal
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import Tuple, Any
|
||||
|
||||
import arrow
|
||||
from pandas import DataFrame
|
||||
import sqlalchemy as sql
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade import exchange
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade.misc import shorten_date
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.state import State
|
||||
from freqtrade import exchange
|
||||
from freqtrade.misc import shorten_date
|
||||
|
||||
|
||||
class RPC(object):
|
||||
@ -30,7 +33,7 @@ class RPC(object):
|
||||
level=self.freqtrade.config.get('loglevel')
|
||||
).get_logger()
|
||||
|
||||
def rpc_trade_status(self) -> (bool, Trade):
|
||||
def rpc_trade_status(self) -> Tuple[bool, Any]:
|
||||
"""
|
||||
Below follows the RPC backend it is prefixed with rpc_ to raise awareness that it is
|
||||
a remotely exposed function
|
||||
@ -39,9 +42,9 @@ class RPC(object):
|
||||
# Fetch open trade
|
||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
if self.freqtrade.get_state() != State.RUNNING:
|
||||
return (True, '*Status:* `trader is not running`')
|
||||
return True, '*Status:* `trader is not running`'
|
||||
elif not trades:
|
||||
return (True, '*Status:* `no active trade`')
|
||||
return True, '*Status:* `no active trade`'
|
||||
else:
|
||||
result = []
|
||||
for trade in trades:
|
||||
@ -80,14 +83,14 @@ class RPC(object):
|
||||
) if order else None,
|
||||
)
|
||||
result.append(message)
|
||||
return (False, result)
|
||||
return False, result
|
||||
|
||||
def rpc_status_table(self) -> (bool, DataFrame):
|
||||
def rpc_status_table(self) -> Tuple[bool, Any]:
|
||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
if self.freqtrade.get_state() != State.RUNNING:
|
||||
return (True, '*Status:* `trader is not running`')
|
||||
return True, '*Status:* `trader is not running`'
|
||||
elif not trades:
|
||||
return (True, '*Status:* `no active order`')
|
||||
return True, '*Status:* `no active order`'
|
||||
else:
|
||||
trades_list = []
|
||||
for trade in trades:
|
||||
@ -107,14 +110,16 @@ class RPC(object):
|
||||
# consisting of (error_occured?, result)
|
||||
# Another approach would be to just return the
|
||||
# result, or raise error
|
||||
return (False, df_statuses)
|
||||
return False, df_statuses
|
||||
|
||||
def rpc_daily_profit(self, timescale, stake_currency, fiat_display_currency):
|
||||
def rpc_daily_profit(
|
||||
self, timescale: int,
|
||||
stake_currency: str, fiat_display_currency: str) -> Tuple[bool, Any]:
|
||||
today = datetime.utcnow().date()
|
||||
profit_days = {}
|
||||
|
||||
if not (isinstance(timescale, int) and timescale > 0):
|
||||
return (True, '*Daily [n]:* `must be an integer greater than 0`')
|
||||
return True, '*Daily [n]:* `must be an integer greater than 0`'
|
||||
|
||||
fiat = self.freqtrade.fiat_converter
|
||||
for day in range(0, timescale):
|
||||
@ -153,9 +158,10 @@ class RPC(object):
|
||||
]
|
||||
for key, value in profit_days.items()
|
||||
]
|
||||
return (False, stats)
|
||||
return False, stats
|
||||
|
||||
def rpc_trade_statistics(self, stake_currency, fiat_display_currency) -> None:
|
||||
def rpc_trade_statistics(
|
||||
self, stake_currency: str, fiat_display_currency: str) -> Tuple[bool, Any]:
|
||||
"""
|
||||
:return: cumulative profit statistics.
|
||||
"""
|
||||
@ -190,15 +196,13 @@ class RPC(object):
|
||||
profit_all_percent.append(profit_percent)
|
||||
|
||||
best_pair = Trade.session.query(
|
||||
Trade.pair,
|
||||
sql.func.sum(Trade.close_profit).label('profit_sum')
|
||||
)\
|
||||
.filter(Trade.is_open.is_(False))\
|
||||
Trade.pair, sql.func.sum(Trade.close_profit).label('profit_sum')
|
||||
).filter(Trade.is_open.is_(False)) \
|
||||
.group_by(Trade.pair) \
|
||||
.order_by(sql.text('profit_sum DESC')).first()
|
||||
|
||||
if not best_pair:
|
||||
return (True, '*Status:* `no closed trade`')
|
||||
return True, '*Status:* `no closed trade`'
|
||||
|
||||
bp_pair, bp_rate = best_pair
|
||||
|
||||
@ -239,7 +243,7 @@ class RPC(object):
|
||||
}
|
||||
)
|
||||
|
||||
def rpc_balance(self, fiat_display_currency):
|
||||
def rpc_balance(self, fiat_display_currency: str) -> Tuple[bool, Any]:
|
||||
"""
|
||||
:return: current account balance per crypto
|
||||
"""
|
||||
@ -248,7 +252,7 @@ class RPC(object):
|
||||
if c['Balance'] or c['Available'] or c['Pending']
|
||||
]
|
||||
if not balances:
|
||||
return (True, '`All balances are zero.`')
|
||||
return True, '`All balances are zero.`'
|
||||
|
||||
output = []
|
||||
total = 0.0
|
||||
@ -275,17 +279,17 @@ class RPC(object):
|
||||
fiat = self.freqtrade.fiat_converter
|
||||
symbol = fiat_display_currency
|
||||
value = fiat.convert_amount(total, 'BTC', symbol)
|
||||
return (False, (output, total, symbol, value))
|
||||
return False, (output, total, symbol, value)
|
||||
|
||||
def rpc_start(self) -> (bool, str):
|
||||
"""
|
||||
Handler for start.
|
||||
"""
|
||||
if self.freqtrade.get_state() == State.RUNNING:
|
||||
return (True, '*Status:* `already running`')
|
||||
return True, '*Status:* `already running`'
|
||||
|
||||
self.freqtrade.update_state(State.RUNNING)
|
||||
return (False, '`Starting trader ...`')
|
||||
return False, '`Starting trader ...`'
|
||||
|
||||
def rpc_stop(self) -> (bool, str):
|
||||
"""
|
||||
@ -293,18 +297,18 @@ class RPC(object):
|
||||
"""
|
||||
if self.freqtrade.get_state() == State.RUNNING:
|
||||
self.freqtrade.update_state(State.STOPPED)
|
||||
return (False, '`Stopping trader ...`')
|
||||
return False, '`Stopping trader ...`'
|
||||
|
||||
return (True, '*Status:* `already stopped`')
|
||||
return True, '*Status:* `already stopped`'
|
||||
|
||||
# FIX: no test for this!!!!
|
||||
def rpc_forcesell(self, trade_id) -> None:
|
||||
def rpc_forcesell(self, trade_id) -> Tuple[bool, Any]:
|
||||
"""
|
||||
Handler for forcesell <id>.
|
||||
Sells the given trade at current price
|
||||
:return: error or None
|
||||
"""
|
||||
def _exec_forcesell(trade: Trade) -> str:
|
||||
def _exec_forcesell(trade: Trade) -> None:
|
||||
# Check if there is there is an open order
|
||||
if trade.open_order_id:
|
||||
order = exchange.get_order(trade.open_order_id)
|
||||
@ -326,13 +330,13 @@ class RPC(object):
|
||||
# ---- EOF def _exec_forcesell ----
|
||||
|
||||
if self.freqtrade.get_state() != State.RUNNING:
|
||||
return (True, '`trader is not running`')
|
||||
return True, '`trader is not running`'
|
||||
|
||||
if trade_id == 'all':
|
||||
# Execute sell for all open orders
|
||||
for trade in Trade.query.filter(Trade.is_open.is_(True)).all():
|
||||
_exec_forcesell(trade)
|
||||
return (False, '')
|
||||
return False, ''
|
||||
|
||||
# Query for trade
|
||||
trade = Trade.query.filter(
|
||||
@ -343,18 +347,18 @@ class RPC(object):
|
||||
).first()
|
||||
if not trade:
|
||||
self.logger.warning('forcesell: Invalid argument received')
|
||||
return (True, 'Invalid argument.')
|
||||
return True, 'Invalid argument.'
|
||||
|
||||
_exec_forcesell(trade)
|
||||
return (False, '')
|
||||
return False, ''
|
||||
|
||||
def rpc_performance(self) -> None:
|
||||
def rpc_performance(self) -> Tuple[bool, Any]:
|
||||
"""
|
||||
Handler for performance.
|
||||
Shows a performance statistic from finished trades
|
||||
"""
|
||||
if self.freqtrade.get_state() != State.RUNNING:
|
||||
return (True, '`trader is not running`')
|
||||
return True, '`trader is not running`'
|
||||
|
||||
pair_rates = Trade.session.query(Trade.pair,
|
||||
sql.func.sum(Trade.close_profit).label('profit_sum'),
|
||||
@ -367,15 +371,15 @@ class RPC(object):
|
||||
for (pair, rate, count) in pair_rates:
|
||||
trades.append({'pair': pair, 'profit': round(rate * 100, 2), 'count': count})
|
||||
|
||||
return (False, trades)
|
||||
return False, trades
|
||||
|
||||
def rpc_count(self) -> None:
|
||||
def rpc_count(self) -> Tuple[bool, Any]:
|
||||
"""
|
||||
Returns the number of trades running
|
||||
:return: None
|
||||
"""
|
||||
if self.freqtrade.get_state() != State.RUNNING:
|
||||
return (True, '`trader is not running`')
|
||||
return True, '`trader is not running`'
|
||||
|
||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
return (False, trades)
|
||||
return False, trades
|
||||
|
@ -28,7 +28,7 @@ class RPCManager(object):
|
||||
self.telegram = None
|
||||
self._init()
|
||||
|
||||
def _init(self):
|
||||
def _init(self) -> None:
|
||||
"""
|
||||
Init RPC modules
|
||||
:return:
|
||||
|
@ -5,10 +5,12 @@ This module manage Telegram communication
|
||||
"""
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
from tabulate import tabulate
|
||||
from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update
|
||||
from telegram.error import NetworkError, TelegramError
|
||||
from telegram.ext import CommandHandler, Updater
|
||||
|
||||
from freqtrade.__init__ import __version__
|
||||
from freqtrade.rpc.rpc import RPC
|
||||
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from freqtrade.indicator_helpers import fishers_inverse
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
|
||||
class_name = 'DefaultStrategy'
|
||||
|
||||
|
@ -4,6 +4,7 @@ This module defines the interface to apply for strategies
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
|
@ -7,11 +7,12 @@ import importlib
|
||||
import os
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from pandas import DataFrame
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade.constants import Constants
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import Constants
|
||||
from freqtrade.logger import Logger
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
|
||||
sys.path.insert(0, r'../../user_data/strategies')
|
||||
|
||||
@ -59,7 +60,7 @@ class Strategy(object):
|
||||
# Minimal ROI designed for the strategy
|
||||
self.minimal_roi = OrderedDict(sorted(
|
||||
{int(key): value for (key, value) in self.custom_strategy.minimal_roi.items()}.items(),
|
||||
key=lambda tuple: tuple[0])) # sort after converting to number
|
||||
key=lambda t: t[0])) # sort after converting to number
|
||||
|
||||
# Optimal stoploss designed for the strategy
|
||||
self.stoploss = float(self.custom_strategy.stoploss)
|
||||
|
@ -1,14 +1,15 @@
|
||||
# pragma pylint: disable=missing-docstring
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock
|
||||
from functools import reduce
|
||||
import logging
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from functools import reduce
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import arrow
|
||||
import pytest
|
||||
from jsonschema import validate
|
||||
from telegram import Chat, Message, Update
|
||||
from sqlalchemy import create_engine
|
||||
from telegram import Chat, Message, Update
|
||||
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.constants import Constants
|
||||
|
@ -1,15 +1,16 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103, bad-continuation, global-statement
|
||||
# pragma pylint: disable=protected-access
|
||||
from unittest.mock import MagicMock
|
||||
from random import randint
|
||||
import logging
|
||||
from requests.exceptions import RequestException
|
||||
import pytest
|
||||
from random import randint
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
import freqtrade.exchange as exchange
|
||||
from freqtrade import OperationalException
|
||||
from freqtrade.exchange import init, validate_pairs, buy, sell, get_balance, get_balances, \
|
||||
get_ticker, get_ticker_history, cancel_order, get_name, get_fee
|
||||
import freqtrade.exchange as exchange
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
API_INIT = False
|
||||
|
@ -1,10 +1,12 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103, protected-access, unused-argument
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from requests.exceptions import ContentDecodingError
|
||||
from freqtrade.exchange.bittrex import Bittrex
|
||||
|
||||
import freqtrade.exchange.bittrex as btx
|
||||
from freqtrade.exchange.bittrex import Bittrex
|
||||
|
||||
|
||||
# Eat this flake8
|
||||
|
@ -1,20 +1,21 @@
|
||||
# pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument
|
||||
|
||||
import json
|
||||
import random
|
||||
import math
|
||||
from typing import List
|
||||
import random
|
||||
from copy import deepcopy
|
||||
from typing import List
|
||||
from unittest.mock import MagicMock
|
||||
from arrow import Arrow
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from freqtrade import optimize
|
||||
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.tests.conftest import default_conf, log_has
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from arrow import Arrow
|
||||
|
||||
from freqtrade import optimize
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
|
||||
from freqtrade.tests.conftest import default_conf, log_has
|
||||
|
||||
# Avoid to reinit the same object again and again
|
||||
_BACKTESTING = Backtesting(default_conf())
|
||||
|
@ -3,6 +3,7 @@ import json
|
||||
import os
|
||||
from copy import deepcopy
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||
|
@ -1,13 +1,14 @@
|
||||
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
||||
|
||||
import os
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
from shutil import copyfile
|
||||
|
||||
from freqtrade import optimize
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.optimize.__init__ import make_testdata_path, download_pairs, \
|
||||
download_backtesting_testdata, load_tickerdata_file, trim_tickerlist
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
# Change this if modifying BTC_UNITEST testdatafile
|
||||
|
@ -6,23 +6,23 @@ Unit test file for rpc/telegram.py
|
||||
"""
|
||||
|
||||
import re
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from random import randint
|
||||
from unittest.mock import MagicMock
|
||||
from copy import deepcopy
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from telegram import Update, Message, Chat
|
||||
from telegram.error import NetworkError
|
||||
|
||||
from freqtrade import __version__
|
||||
from freqtrade.rpc.telegram import authorized_only
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.rpc.telegram import Telegram
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc.telegram import Telegram
|
||||
from freqtrade.rpc.telegram import authorized_only
|
||||
from freqtrade.state import State
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal, patch_coinmarketcap
|
||||
from freqtrade.tests.conftest import get_patched_freqtradebot, log_has
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal, patch_coinmarketcap
|
||||
|
||||
|
||||
class DummyCls(Telegram):
|
||||
|
@ -1,8 +1,10 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy, class_name
|
||||
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy, class_name
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -1,6 +1,7 @@
|
||||
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
||||
|
||||
import logging
|
||||
|
||||
from freqtrade.strategy.strategy import Strategy
|
||||
|
||||
|
||||
|
@ -5,8 +5,9 @@ Unit test file for analyse.py
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from unittest.mock import MagicMock
|
||||
import logging
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import arrow
|
||||
from pandas import DataFrame
|
||||
|
||||
@ -14,7 +15,6 @@ from freqtrade.analyze import Analyze, SignalType
|
||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
|
||||
# Avoid to reinit the same object again and again
|
||||
_ANALYZE = Analyze({'strategy': 'default_strategy'})
|
||||
|
||||
|
@ -6,6 +6,7 @@ Unit test file for arguments.py
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.arguments import Arguments
|
||||
|
@ -4,10 +4,10 @@
|
||||
Unit test file for configuration.py
|
||||
"""
|
||||
import json
|
||||
|
||||
from copy import deepcopy
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from jsonschema import ValidationError
|
||||
|
||||
from freqtrade.arguments import Arguments
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
import pandas
|
||||
|
||||
from freqtrade.optimize import load_data
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.optimize import load_data
|
||||
from freqtrade.strategy.strategy import Strategy
|
||||
|
||||
_pairs = ['BTC_ETH']
|
||||
|
@ -5,22 +5,23 @@ Unit test file for freqtradebot.py
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from unittest.mock import MagicMock
|
||||
from copy import deepcopy
|
||||
from typing import Dict, Optional
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import arrow
|
||||
import pytest
|
||||
import requests
|
||||
import re
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from freqtrade.tests.conftest import log_has
|
||||
from freqtrade import DependencyException, OperationalException
|
||||
from freqtrade.exchange import Exchanges
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.state import State
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.state import State
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
|
@ -1,4 +1,5 @@
|
||||
import pandas as pd
|
||||
|
||||
from freqtrade.indicator_helpers import went_up, went_down
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@ Unit test file for logger.py
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from freqtrade.logger import Logger
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@ Unit test file for main.py
|
||||
|
||||
import logging
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.main import main, set_loggers
|
||||
|
@ -6,10 +6,11 @@ Unit test file for misc.py
|
||||
|
||||
import datetime
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||
from freqtrade.misc import (shorten_date, datesarray_to_datetimearray,
|
||||
common_datearray, file_dump_json)
|
||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||
|
||||
|
||||
def test_shorten_date() -> None:
|
||||
|
@ -1,7 +1,9 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from freqtrade.exchange import Exchanges
|
||||
from freqtrade.persistence import Trade, init, clean_dry_run_db
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""This script generate json data from bittrex"""
|
||||
import sys
|
||||
import json
|
||||
import sys
|
||||
|
||||
from freqtrade import exchange
|
||||
from freqtrade.exchange import Bittrex
|
||||
from freqtrade import misc
|
||||
from freqtrade.exchange import Bittrex
|
||||
|
||||
parser = misc.common_args_parser('download utility')
|
||||
parser.add_argument(
|
||||
|
@ -13,8 +13,9 @@ Optional Cli parameters
|
||||
"""
|
||||
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
|
||||
from plotly import tools
|
||||
from plotly.offline import plot
|
||||
@ -30,10 +31,9 @@ import freqtrade.optimize as optimize
|
||||
logger = Logger(name="Graph dataframe").get_logger()
|
||||
|
||||
|
||||
def plot_analyzed_dataframe(args) -> None:
|
||||
def plot_analyzed_dataframe(args: Namespace) -> None:
|
||||
"""
|
||||
Calls analyze() and plots the returned dataframe
|
||||
:param pair: pair as str
|
||||
:return: None
|
||||
"""
|
||||
pair = args.pair.replace('-', '_')
|
||||
@ -153,7 +153,7 @@ def plot_analyzed_dataframe(args) -> None:
|
||||
plot(fig, filename='freqtrade-plot.html')
|
||||
|
||||
|
||||
def plot_parse_args(args):
|
||||
def plot_parse_args(args: List[str]) -> Namespace:
|
||||
"""
|
||||
Parse args passed to the script
|
||||
:param args: Cli arguments
|
||||
@ -168,7 +168,7 @@ def plot_parse_args(args):
|
||||
return arguments.parse_args()
|
||||
|
||||
|
||||
def main(sysargv: Dict) -> None:
|
||||
def main(sysargv: List[str]) -> None:
|
||||
"""
|
||||
This function will initiate the bot and start the trading loop.
|
||||
:return: None
|
||||
|
@ -13,7 +13,8 @@ Optional Cli parameters
|
||||
|
||||
import sys
|
||||
import json
|
||||
from typing import Dict
|
||||
from argparse import Namespace
|
||||
from typing import List, Optional
|
||||
import numpy as np
|
||||
|
||||
from plotly import tools
|
||||
@ -34,8 +35,11 @@ logger = Logger(name="Graph profits").get_logger()
|
||||
|
||||
# data:: [ pair, profit-%, enter, exit, time, duration]
|
||||
# data:: ["BTC_ETH", 0.0023975, "1515598200", "1515602100", "2018-01-10 07:30:00+00:00", 65]
|
||||
def make_profit_array(data, px, min_date, interval, filter_pairs=[]):
|
||||
def make_profit_array(
|
||||
data: List, px: int, min_date: int,
|
||||
interval: int, filter_pairs: Optional[List] = None) -> np.ndarray:
|
||||
pg = np.zeros(px)
|
||||
filter_pairs = filter_pairs or []
|
||||
# Go through the trades
|
||||
# and make an total profit
|
||||
# array
|
||||
@ -63,7 +67,7 @@ def make_profit_array(data, px, min_date, interval, filter_pairs=[]):
|
||||
return pg
|
||||
|
||||
|
||||
def plot_profit(args) -> None:
|
||||
def plot_profit(args: Namespace) -> None:
|
||||
"""
|
||||
Plots the total profit for all pairs.
|
||||
Note, the profit calculation isn't realistic.
|
||||
@ -183,14 +187,14 @@ def plot_profit(args) -> None:
|
||||
plot(fig, filename='freqtrade-profit-plot.html')
|
||||
|
||||
|
||||
def define_index(min_date, max_date, interval):
|
||||
def define_index(min_date: int, max_date: int, interval: int) -> int:
|
||||
"""
|
||||
Return the index of a specific date
|
||||
"""
|
||||
return int((max_date - min_date) / (interval * 60))
|
||||
|
||||
|
||||
def plot_parse_args(args):
|
||||
def plot_parse_args(args: List[str]) -> Namespace:
|
||||
"""
|
||||
Parse args passed to the script
|
||||
:param args: Cli arguments
|
||||
@ -205,7 +209,7 @@ def plot_parse_args(args):
|
||||
return arguments.parse_args()
|
||||
|
||||
|
||||
def main(sysargv: Dict) -> None:
|
||||
def main(sysargv: List[str]) -> None:
|
||||
"""
|
||||
This function will initiate the bot and start the trading loop.
|
||||
:return: None
|
||||
|
Loading…
Reference in New Issue
Block a user