stable/freqtrade/persistence/models.py

90 lines
3.0 KiB
Python
Raw Normal View History

2018-03-02 15:22:00 +00:00
"""
This module contains the class to persist trades into SQLite
"""
import logging
2017-05-12 17:11:56 +00:00
from sqlalchemy import create_engine, inspect
2018-06-07 19:35:57 +00:00
from sqlalchemy.exc import NoSuchModuleError
from sqlalchemy.orm import scoped_session, sessionmaker
2017-11-09 22:45:22 +00:00
from sqlalchemy.pool import StaticPool
2017-05-12 17:11:56 +00:00
from freqtrade.exceptions import OperationalException
from freqtrade.persistence.base import _DECL_BASE
2020-08-13 06:33:46 +00:00
from freqtrade.persistence.migrations import check_migrate
from freqtrade.persistence.pairlock import PairLock
from freqtrade.persistence.trade_model import Order, Trade
2018-06-07 19:35:57 +00:00
2020-09-28 17:39:41 +00:00
logger = logging.getLogger(__name__)
2019-09-10 07:42:45 +00:00
2018-06-23 13:27:29 +00:00
_SQL_DOCS_URL = 'http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls'
2017-05-12 17:11:56 +00:00
2020-10-16 05:39:12 +00:00
def init_db(db_url: str, clean_open_orders: bool = False) -> None:
"""
2021-11-09 18:22:29 +00:00
Initializes this module with the given config,
registers all known command handlers
and starts polling for message updates
:param db_url: Database to use
:param clean_open_orders: Remove open orders from the database.
Useful for dry-run or if all orders have been reset on the exchange.
:return: None
"""
kwargs = {}
2022-02-22 18:39:55 +00:00
if db_url == 'sqlite:///':
raise OperationalException(
f'Bad db-url {db_url}. For in-memory database, please use `sqlite://`.')
if db_url == 'sqlite://':
kwargs.update({
'poolclass': StaticPool,
2021-05-23 06:56:41 +00:00
})
# Take care of thread ownership
if db_url.startswith('sqlite://'):
kwargs.update({
'connect_args': {'check_same_thread': False},
})
2018-06-07 19:35:57 +00:00
try:
2021-04-13 15:34:20 +00:00
engine = create_engine(db_url, future=True, **kwargs)
2018-06-07 19:35:57 +00:00
except NoSuchModuleError:
raise OperationalException(f"Given value for db_url: '{db_url}' "
f"is no valid database URL! (See {_SQL_DOCS_URL})")
2018-06-07 19:35:57 +00:00
2019-10-29 13:26:03 +00:00
# https://docs.sqlalchemy.org/en/13/orm/contextual.html#thread-local-scope
# Scoped sessions proxy requests to the appropriate thread-local session.
# We should use the scoped_session object - not a seperately initialized version
2021-04-13 15:34:20 +00:00
Trade._session = scoped_session(sessionmaker(bind=engine, autoflush=True))
2021-04-05 06:46:12 +00:00
Trade.query = Trade._session.query_property()
Order.query = Trade._session.query_property()
PairLock.query = Trade._session.query_property()
2020-10-17 09:28:34 +00:00
previous_tables = inspect(engine).get_table_names()
2017-11-07 19:13:36 +00:00
_DECL_BASE.metadata.create_all(engine)
check_migrate(engine, decl_base=_DECL_BASE, previous_tables=previous_tables)
# Clean dry_run DB if the db is not in-memory
if clean_open_orders and db_url != 'sqlite://':
clean_dry_run_db()
2020-10-16 05:39:12 +00:00
def cleanup_db() -> None:
"""
Flushes all pending operations to disk.
:return: None
"""
2021-04-15 05:57:52 +00:00
Trade.commit()
def clean_dry_run_db() -> None:
"""
Remove open_order_id from a Dry_run DB
:return: None
"""
for trade in Trade.query.filter(Trade.open_order_id.isnot(None)).all():
# Check we are updating only a dry_run order not a prod one
if 'dry_run' in trade.open_order_id:
trade.open_order_id = None
2021-04-15 05:57:52 +00:00
Trade.commit()