Skip to content

Commit

Permalink
Merge pull request #43 from EtWnn/develop
Browse files Browse the repository at this point in the history
Release v0.1.3
  • Loading branch information
EtWnn authored Apr 6, 2021
2 parents 824daf4 + f81b859 commit c7d6ddd
Show file tree
Hide file tree
Showing 13 changed files with 248 additions and 45 deletions.
20 changes: 11 additions & 9 deletions BinanceWatch/BinanceManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ class BinanceManager:

def __init__(self, api_key: str, api_secret: str, account_name: str = 'default'):
"""
initialise the binance manager.
Initialise the binance manager.
:param api_key: key for the Binance api
:type api_key: str
:param api_secret: secret for the Binance api
:type api_secret: str
:param account_name: if you have several accounts to monitor, you need to give them different names or the
database will collide
database will collide
:type account_name: str
"""
self.account_name = account_name
Expand Down Expand Up @@ -231,7 +231,7 @@ def update_margin_asset_repay(self, asset: str, isolated_symbol=''):
while True:
client_params = {
'asset': asset,
'current':current,
'current': current,
'startTime': latest_time + 1000,
'archived': archived,
'isolatedSymbol': isolated_symbol,
Expand Down Expand Up @@ -611,7 +611,7 @@ def update_spot_dividends(self, day_jump: float = 90, limit: int = 500):
)
pbar.update()
if len(dividends) < limit:
start_time += delta_jump
start_time += delta_jump + 1 # endTime is included in the previous return, so we have to add 1
else: # limit was reached before the end of the time windows
start_time = int(dividends[0]['divTime']) + 1
if len(dividends):
Expand Down Expand Up @@ -658,7 +658,7 @@ def update_spot_withdraws(self, day_jump: float = 90):
auto_commit=False
)
pbar.update()
start_time += delta_jump
start_time += delta_jump + 1 # endTime is included in the previous return, so we have to add 1
if len(withdraws):
self.db.commit()
pbar.close()
Expand Down Expand Up @@ -700,7 +700,7 @@ def update_spot_deposits(self, day_jump: float = 90):
amount=float(deposit['amount']),
auto_commit=False)
pbar.update()
start_time += delta_jump
start_time += delta_jump + 1 # endTime is included in the previous return, so we have to add 1
if len(deposits):
self.db.commit()
pbar.close()
Expand Down Expand Up @@ -795,11 +795,13 @@ def _call_binance_client(self, method_name: str, params: Optional[Dict] = None,
return getattr(self.client, method_name)(**params)
except BinanceAPIException as err:
if err.code == -1003: # API rate Limits
wait_time = float(err.response.headers['Retry-After'])
# wait_time = float(err.response.headers['Retry-After']) it seems to be always 0, so unusable
wait_time = 1 + 60 - datetime.datetime.now().timestamp() % 60 # number of seconds until next minute
if err.response.status_code == 418: # ban
self.logger.error(f"API calls resulted in a ban, retry in {wait_time} seconds")
raise err
self.logger.info(f"API calls resulted in a breach of rate limits, will retry after {wait_time} seconds")
time.sleep(wait_time + 1)
self.logger.info(f"API calls resulted in a breach of rate limits,"
f" will retry after {wait_time:.2f} seconds")
time.sleep(wait_time)
return self._call_binance_client(method_name, params, retry_count + 1)
raise err
2 changes: 1 addition & 1 deletion BinanceWatch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "0.1.2"
__version__ = "0.1.3"
__author__ = 'EtWnn'
6 changes: 6 additions & 0 deletions BinanceWatch/storage/BinanceDataBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ class BinanceDataBase(DataBase):
"""

def __init__(self, name: str = 'binance_db'):
"""
Initialise a binance database instance
:param name: name of the database
:type name: str
"""
super().__init__(name)

def add_universal_transfer(self, transfer_id: int, transfer_type: str, transfer_time: int, asset: str,
Expand Down
173 changes: 142 additions & 31 deletions BinanceWatch/storage/DataBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

class SQLConditionEnum(Enum):
"""
Enumeration for SQL comparison operator
https://www.techonthenet.com/sqlite/comparison_operators.php
"""
equal = '='
Expand All @@ -25,17 +27,46 @@ class DataBase:
"""

def __init__(self, name: str):
"""
Initialise a DataBase instance
:param name: name of the database
:type name: str
"""
self.name = name
self.logger = LoggerGenerator.get_logger(self.name)
self.save_path = get_data_path() / f"{name}.db"
self.db_conn = None
self.db_cursor = None
self.connect()

def connect(self):
"""
Connect to the sqlite3 database
:return: None
:rtype: None
"""
self.db_conn = sqlite3.connect(self.save_path)
self.db_cursor = self.db_conn.cursor()

def _fetch_rows(self, execution_cmd: str):
def close(self):
"""
Close the connection with the sqlite3 database
:return: None
:rtype: None
"""
self.db_conn.close()

def _fetch_rows(self, execution_cmd: str) -> List[Tuple]:
"""
execute a command to fetch some rows and return them
Execute a command to fetch some rows and return them
:param execution_cmd: the command to execute
:return:
:type execution_cmd: str
:return: list of the table's rows selected by the command
:rtype: List[Tuple]
"""
rows = []
try:
Expand All @@ -51,10 +82,14 @@ def _fetch_rows(self, execution_cmd: str):

def get_row_by_key(self, table: Table, key_value) -> Optional[Tuple]:
"""
get the row identified by a primary key value from a table
:param table: table to fetch the row from
:param key_value: key value of the row
:return: None or the row of value
Get the row identified by a primary key value from a table
:param table: table to fetch the key from
:type table: Table
:param key_value: value of the primary key
:type key_value: Any
:return: the raw row of of the table
:rtype: Optional[Tuple]
"""
if table.primary_key is None:
raise ValueError(f"table {table.name} has no explicit primary key")
Expand All @@ -64,12 +99,24 @@ def get_row_by_key(self, table: Table, key_value) -> Optional[Tuple]:
return rows[0]

def get_conditions_rows(self, table: Table,
selection: Optional[Union[str, List[str]]] = None,
selection: Union[str, List[str]] = '*',
conditions_list: Optional[List[Tuple[str, SQLConditionEnum, Any]]] = None,
order_list: Optional[List[str]] = None) -> List:
if selection is None:
selection = '*'
elif isinstance(selection, List):
order_list: Optional[List[str]] = None) -> List[Tuple]:
"""
Select rows with optional conditions and optional order
:param table: table to select the rows from
:type table: Table
:param selection: list of column or SQL type selection
:type selection: Union[str, List[str]]
:param conditions_list: list of conditions to select the row
:type conditions_list: Optional[List[Tuple[str, SQLConditionEnum, Any]]]
:param order_list: List of SQL type order by
:type order_list: Optional[List[str]]
:return: the selected rows
:rtype: List[Tuple]
"""
if isinstance(selection, List):
selection = ','.join(selection)
if conditions_list is None:
conditions_list = []
Expand All @@ -80,10 +127,33 @@ def get_conditions_rows(self, table: Table,
execution_cmd = self._add_order(execution_cmd, order_list=order_list)
return self._fetch_rows(execution_cmd)

def get_all_rows(self, table: Table) -> List:
def get_all_rows(self, table: Table) -> List[Tuple]:
"""
Get all the rows of a table
:param table: table to get the rows from
:type table: Table
:return: all the rows of the table
:rtype: List[Tuple]
"""
return self.get_conditions_rows(table)

def add_row(self, table: Table, row: Tuple, auto_commit: bool = True, update_if_exists: bool = False):
"""
Add a row to a table
:param table: table to add a row to
:type table: Table
:param row: values to add to the database
:type row: Tuple
:param auto_commit: if the database state should be saved after the changes
:type auto_commit: bool
:param update_if_exists: if an integrity error is raised and this parameter is true,
will update the existing row
:type update_if_exists: bool
:return: None
:rtype: None
"""
row_s = ", ".join(f"'{v}'" for v in row)
row_s = f'({row_s})'
execution_order = f"INSERT INTO {table.name} VALUES {row_s}"
Expand All @@ -100,15 +170,45 @@ def add_row(self, table: Table, row: Tuple, auto_commit: bool = True, update_if_
if update_if_exists:
self.update_row(table, row, auto_commit)
else:
existing_row = self.get_row_by_key(table, row[0])
msg = f"tried to insert {row} in the table {table.name} but the row is occupied: {existing_row}"
self.logger.error(msg)
raise err

def add_rows(self, table: Table, rows: List[Tuple], auto_commit: bool = True, update_if_exists: bool = False):
"""
Add several rows to a table
:param table: table to add a row to
:type table: Table
:param rows: list of values to add to the database
:type rows: List[Tuple]
:param auto_commit: if the database state should be saved after the changes
:type auto_commit: bool
:param update_if_exists: if an integrity error is raised and this parameter is true,
will update the existing row
:type update_if_exists: bool
:return: None
:rtype: None
"""
for row in rows:
self.add_row(table, row, auto_commit=False, update_if_exists=update_if_exists)
if auto_commit:
self.commit()

def update_row(self, table: Table, row: Tuple, auto_commit=True):
"""
Update the value of a row in a table
:param table: table to get updated
:type table: Table
:param row: values to update
:type row: Tuple
:param auto_commit: if the database state should be saved after the changes
:type auto_commit: bool
:return: None
:rtype: None
"""
row_s = ", ".join(f"{n} = {v}" for n, v in zip(table.columns_names, row))
execution_order = f"UPDATE {table.name} SET {row_s} WHERE {table.primary_key} = {row[0]}"
self.db_cursor.execute(execution_order)
Expand All @@ -117,20 +217,23 @@ def update_row(self, table: Table, row: Tuple, auto_commit=True):

def create_table(self, table: Table):
"""
create a table in the database
Create a table in the database
:param table: Table instance with the config of the table to create
:return:
:type table: Table
:return: None
:rtype: None
"""
create_cmd = self.get_create_cmd(table)
self.db_cursor.execute(create_cmd)
self.db_conn.commit()

def drop_table(self, table: Union[Table, str]):
"""
delete a table from the database
Delete a table from the database
:param table: table or table name to drop
:type table: str or Table instance
:type table: Union[Table, str]
:return: None
:rtype: None
"""
Expand All @@ -142,7 +245,7 @@ def drop_table(self, table: Union[Table, str]):

def drop_all_tables(self):
"""
drop all the tables existing in the database
Drop all the tables existing in the database
:return: None
:rtype: None
Expand All @@ -154,7 +257,7 @@ def drop_all_tables(self):

def get_all_tables(self) -> List[Tuple]:
"""
return all the tables existing in the database
Return all the tables existing in the database
:return: tables descriptions
:rtype: List[Tuple]
Expand All @@ -164,19 +267,24 @@ def get_all_tables(self) -> List[Tuple]:

def commit(self):
"""
submit and save the database state
:return:
Submit and save the database state
:return: None
:rtype: None
"""
self.db_conn.commit()

@staticmethod
def _add_conditions(execution_cmd: str, conditions_list: List[Tuple[str, SQLConditionEnum, Any]]):
"""
add a list of condition to an SQL command
Add a list of condition to an SQL command
:param execution_cmd: SQL command without 'WHERE' statement
:type execution_cmd: str
:param conditions_list:
:return:
:param conditions_list: List of condition to add to the SQL command
:type conditions_list: List[Tuple[str, SQLConditionEnum, Any]]
:return: the augmented command
:rtype: str
"""
if len(conditions_list):
add_cmd = ' WHERE'
Expand All @@ -189,14 +297,14 @@ def _add_conditions(execution_cmd: str, conditions_list: List[Tuple[str, SQLCond
@staticmethod
def _add_order(execution_cmd: str, order_list: List[str]):
"""
add an order specification to an SQL command
Add an order specification to an SQL command
:param execution_cmd: SQL command without 'ORDER BY' statement
:type execution_cmd: str
:param order_list:
:type order_list:
:return:
:rtype:
:param order_list: SQL order
:type order_list: List[str]
:return: the augmented command
:rtype: str
"""
if len(order_list):
add_cmd = ' ORDER BY'
Expand All @@ -207,11 +315,14 @@ def _add_order(execution_cmd: str, order_list: List[str]):
return execution_cmd

@staticmethod
def get_create_cmd(table: Table):
def get_create_cmd(table: Table) -> str:
"""
return the command in string format to create a table in the database
Return the command in string format to create a table in the database
:param table: Table instance with the config if the table to create
:type table: Table
:return: execution command for the table creation
:rtype: str
"""
cmd = ""
if table.primary_key is not None:
Expand Down
Loading

0 comments on commit c7d6ddd

Please sign in to comment.