add typehints

This commit is contained in:
gcarq 2017-09-01 21:11:46 +02:00
parent 99cbf72dc4
commit 32cac11580
6 changed files with 44 additions and 38 deletions

View File

@ -38,7 +38,7 @@ 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.
##### Prerequisites ##### Prerequisites
* python3 * python3.6
* sqlite * sqlite
##### Install ##### Install

View File

@ -11,7 +11,7 @@ logging.basicConfig(level=logging.DEBUG,
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_ticker_dataframe(pair): def get_ticker_dataframe(pair: str) -> StockDataFrame:
""" """
Analyses the trend for the given pair Analyses the trend for the given pair
:param pair: pair as str in format BTC_ETH or BTC-ETH :param pair: pair as str in format BTC_ETH or BTC-ETH
@ -51,7 +51,7 @@ def get_ticker_dataframe(pair):
return dataframe return dataframe
def populate_trends(dataframe): def populate_trends(dataframe: StockDataFrame) -> StockDataFrame:
""" """
Populates the trends for the given dataframe Populates the trends for the given dataframe
:param dataframe: StockDataFrame :param dataframe: StockDataFrame
@ -73,7 +73,7 @@ def populate_trends(dataframe):
return dataframe return dataframe
def get_buy_signal(pair): def get_buy_signal(pair: str) -> bool:
""" """
Calculates a buy signal based on StochRSI indicator Calculates a buy signal based on StochRSI indicator
:param pair: pair in format BTC_ANT or BTC-ANT :param pair: pair in format BTC_ANT or BTC-ANT
@ -93,7 +93,7 @@ def get_buy_signal(pair):
return signal return signal
def plot_dataframe(dataframe, pair): def plot_dataframe(dataframe: StockDataFrame, pair: str) -> None:
""" """
Plots the given dataframe Plots the given dataframe
:param dataframe: StockDataFrame :param dataframe: StockDataFrame

View File

@ -1,5 +1,7 @@
import enum import enum
import logging import logging
from typing import List
from bittrex.bittrex import Bittrex from bittrex.bittrex import Bittrex
from poloniex import Poloniex from poloniex import Poloniex
from wrapt import synchronized from wrapt import synchronized
@ -9,18 +11,6 @@ logger = logging.getLogger(__name__)
_exchange_api = None _exchange_api = None
@synchronized
def get_exchange_api(conf):
"""
Returns the current exchange api or instantiates a new one
:return: exchange.ApiWrapper
"""
global _exchange_api
if not _exchange_api:
_exchange_api = ApiWrapper(conf)
return _exchange_api
class Exchange(enum.Enum): class Exchange(enum.Enum):
POLONIEX = 0 POLONIEX = 0
BITTREX = 1 BITTREX = 1
@ -33,7 +23,7 @@ class ApiWrapper(object):
* Bittrex * Bittrex
* Poloniex (partly) * Poloniex (partly)
""" """
def __init__(self, config): def __init__(self, config: dict):
""" """
Initializes the ApiWrapper with the given config, it does not validate those values. Initializes the ApiWrapper with the given config, it does not validate those values.
:param config: dict :param config: dict
@ -54,13 +44,13 @@ class ApiWrapper(object):
else: else:
self.api = None self.api = None
def buy(self, pair, rate, amount): def buy(self, pair: str, rate: float, amount: float) -> str:
""" """
Places a limit buy order. Places a limit buy order.
:param pair: Pair as str, format: BTC_ETH :param pair: Pair as str, format: BTC_ETH
:param rate: Rate limit for order :param rate: Rate limit for order
:param amount: The amount to purchase :param amount: The amount to purchase
:return: None :return: order_id of the placed buy order
""" """
if self.dry_run: if self.dry_run:
pass pass
@ -73,7 +63,7 @@ class ApiWrapper(object):
raise RuntimeError('BITTREX: {}'.format(data['message'])) raise RuntimeError('BITTREX: {}'.format(data['message']))
return data['result']['uuid'] return data['result']['uuid']
def sell(self, pair, rate, amount): def sell(self, pair: str, rate: float, amount: float) -> str:
""" """
Places a limit sell order. Places a limit sell order.
:param pair: Pair as str, format: BTC_ETH :param pair: Pair as str, format: BTC_ETH
@ -92,7 +82,7 @@ class ApiWrapper(object):
raise RuntimeError('BITTREX: {}'.format(data['message'])) raise RuntimeError('BITTREX: {}'.format(data['message']))
return data['result']['uuid'] return data['result']['uuid']
def get_balance(self, currency): def get_balance(self, currency: str) -> float:
""" """
Get account balance. Get account balance.
:param currency: currency as str, format: BTC :param currency: currency as str, format: BTC
@ -109,7 +99,7 @@ class ApiWrapper(object):
raise RuntimeError('BITTREX: {}'.format(data['message'])) raise RuntimeError('BITTREX: {}'.format(data['message']))
return float(data['result']['Balance'] or 0.0) return float(data['result']['Balance'] or 0.0)
def get_ticker(self, pair): def get_ticker(self, pair: str) -> dict:
""" """
Get Ticker for given pair. Get Ticker for given pair.
:param pair: Pair as str, format: BTC_ETC :param pair: Pair as str, format: BTC_ETC
@ -132,7 +122,7 @@ class ApiWrapper(object):
'last': float(data['result']['Last']), 'last': float(data['result']['Last']),
} }
def cancel_order(self, order_id): def cancel_order(self, order_id: str) -> None:
""" """
Cancel order for given order_id Cancel order for given order_id
:param order_id: id as str :param order_id: id as str
@ -147,7 +137,7 @@ class ApiWrapper(object):
if not data['success']: if not data['success']:
raise RuntimeError('BITTREX: {}'.format(data['message'])) raise RuntimeError('BITTREX: {}'.format(data['message']))
def get_open_orders(self, pair): def get_open_orders(self, pair: str) -> List[dict]:
""" """
Get all open orders for given pair. Get all open orders for given pair.
:param pair: Pair as str, format: BTC_ETC :param pair: Pair as str, format: BTC_ETC
@ -170,7 +160,7 @@ class ApiWrapper(object):
'remaining': entry['QuantityRemaining'], 'remaining': entry['QuantityRemaining'],
} for entry in data['result']] } for entry in data['result']]
def get_pair_detail_url(self, pair): def get_pair_detail_url(self, pair: str) -> str:
""" """
Returns the market detail url for the given pair Returns the market detail url for the given pair
:param pair: pair as str, format: BTC_ANT :param pair: pair as str, format: BTC_ANT
@ -180,3 +170,15 @@ class ApiWrapper(object):
raise NotImplemented('Not implemented') raise NotImplemented('Not implemented')
elif self.exchange == Exchange.BITTREX: elif self.exchange == Exchange.BITTREX:
return 'https://bittrex.com/Market/Index?MarketName={}'.format(pair.replace('_', '-')) return 'https://bittrex.com/Market/Index?MarketName={}'.format(pair.replace('_', '-'))
@synchronized
def get_exchange_api(conf: dict) -> ApiWrapper:
"""
Returns the current exchange api or instantiates a new one
:return: exchange.ApiWrapper
"""
global _exchange_api
if not _exchange_api:
_exchange_api = ApiWrapper(conf)
return _exchange_api

19
main.py
View File

@ -5,11 +5,13 @@ import time
import traceback import traceback
from datetime import datetime from datetime import datetime
from json import JSONDecodeError from json import JSONDecodeError
from typing import Optional
from requests import ConnectionError from requests import ConnectionError
from wrapt import synchronized from wrapt import synchronized
from analyze import get_buy_signal from analyze import get_buy_signal
from persistence import Trade, Session from persistence import Trade, Session
from exchange import get_exchange_api from exchange import get_exchange_api, Exchange
from rpc.telegram import TelegramHandler from rpc.telegram import TelegramHandler
from utils import get_conf from utils import get_conf
@ -32,11 +34,11 @@ class TradeThread(threading.Thread):
super().__init__() super().__init__()
self._should_stop = False self._should_stop = False
def stop(self): def stop(self) -> None:
""" stops the trader thread """ """ stops the trader thread """
self._should_stop = True self._should_stop = True
def run(self): def run(self) -> None:
""" """
Threaded main function Threaded main function
:return: None :return: None
@ -60,7 +62,7 @@ class TradeThread(threading.Thread):
TelegramHandler.send_msg('*Status:* `Trader has stopped`') TelegramHandler.send_msg('*Status:* `Trader has stopped`')
@staticmethod @staticmethod
def _process(): def _process() -> None:
""" """
Queries the persistence layer for open trades and handles them, Queries the persistence layer for open trades and handles them,
otherwise a new trade is created. otherwise a new trade is created.
@ -107,8 +109,9 @@ class TradeThread(threading.Thread):
# Initial stopped TradeThread instance # Initial stopped TradeThread instance
_instance = TradeThread() _instance = TradeThread()
@synchronized @synchronized
def get_instance(recreate=False): def get_instance(recreate: bool=False) -> TradeThread:
""" """
Get the current instance of this thread. This is a singleton. Get the current instance of this thread. This is a singleton.
:param recreate: Must be True if you want to start the instance :param recreate: Must be True if you want to start the instance
@ -122,7 +125,7 @@ def get_instance(recreate=False):
return _instance return _instance
def close_trade_if_fulfilled(trade): def close_trade_if_fulfilled(trade: Trade) -> bool:
""" """
Checks if the trade is closable, and if so it is being closed. Checks if the trade is closable, and if so it is being closed.
:param trade: Trade :param trade: Trade
@ -137,7 +140,7 @@ def close_trade_if_fulfilled(trade):
return False return False
def handle_trade(trade): def handle_trade(trade: Trade) -> None:
""" """
Sells the current pair if the threshold is reached and updates the trade record. Sells the current pair if the threshold is reached and updates the trade record.
:return: None :return: None
@ -178,7 +181,7 @@ def handle_trade(trade):
logger.exception('Unable to handle open order') logger.exception('Unable to handle open order')
def create_trade(stake_amount: float, exchange): def create_trade(stake_amount: float, exchange: Exchange) -> Optional[Trade]:
""" """
Checks the implemented trading indicator(s) for a randomly picked pair, Checks the implemented trading indicator(s) for a randomly picked pair,
if one pair triggers the buy_signal a new trade record gets created if one pair triggers the buy_signal a new trade record gets created

View File

@ -46,7 +46,7 @@ class Trade(Base):
'closed' if not self.is_open else round((datetime.utcnow() - self.open_date).total_seconds() / 60, 2) 'closed' if not self.is_open else round((datetime.utcnow() - self.open_date).total_seconds() / 60, 2)
) )
def exec_sell_order(self, rate, amount): def exec_sell_order(self, rate: float, amount: float) -> float:
""" """
Executes a sell for the given trade and updated the entity. Executes a sell for the given trade and updated the entity.
:param rate: rate to sell for :param rate: rate to sell for

View File

@ -1,5 +1,6 @@
import json import json
import logging import logging
from typing import List
from wrapt import synchronized from wrapt import synchronized
from bittrex.bittrex import Bittrex from bittrex.bittrex import Bittrex
@ -10,7 +11,7 @@ _cur_conf = None
@synchronized @synchronized
def get_conf(filename='config.json'): def get_conf(filename: str='config.json') -> dict:
""" """
Loads the config into memory and returns the instance of it Loads the config into memory and returns the instance of it
:return: dict :return: dict
@ -23,7 +24,7 @@ def get_conf(filename='config.json'):
return _cur_conf return _cur_conf
def validate_conf(conf): def validate_conf(conf: dict) -> None:
""" """
Validates if the minimal possible config is provided Validates if the minimal possible config is provided
:param conf: config as dict :param conf: config as dict
@ -86,7 +87,7 @@ def validate_conf(conf):
logger.info('Config is valid ...') logger.info('Config is valid ...')
def validate_bittrex_pairs(pairs): def validate_bittrex_pairs(pairs: List[str]) -> None:
""" """
Validates if all given pairs exist on bittrex Validates if all given pairs exist on bittrex
:param pairs: list of str :param pairs: list of str