from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm.exc import FlushError
from .. import utils
from ..database.instrument import Instrument
from ..database.timeframe import Timeframe
from ..database.broker import Broker
from ..database.price_data_source import PriceDataSource
from ..database.exchange import Exchange
from ..database.asset import Asset
from ..database.timetable import Timetable
[docs]class Saver():
"""
Class that saves data on the database.
Attributes:
session (sqlalchemy.orm.session.Session): Database connection.
"""
[docs] def __init__(self, session):
"""
Costructor method.
Args:
session (sqlalchemy.orm.session.Session): Database connection.
"""
self.session = session
[docs] def _save(self, obj):
"""
Save an instance of a map class.
Args:
obj (obj): Instance to save.
"""
try:
self.session.add(obj)
self.session.commit()
except (IntegrityError, FlushError):
self.session.rollback()
[docs] def instrument(self, kind):
"""
Save an instrument on the db.
Args:
kind (str): Kind of instrument to save. (instrument_type)
Return:
instrument (alchemist_lib.database.instrument.Instrument): Map class instance.
"""
already_saved = self.session.query(Instrument).filter(Instrument.instrument_type == kind).all()
if len(already_saved) > 0:
return already_saved[0]
instrument = Instrument(instrument_type = kind)
self._save(instrument)
return instrument
[docs] def timeframe(self, id, description):
"""
Save a timeframe on the db.
Args:
if (str): Timeframe identifier. (15M as example).
description (str): The definition of the timeframe in english words. (fifteen minutes as example).
Return:
tf (alchemist_lib.database.timeframe.Timeframe): Map class instance.
"""
tf = Timeframe(timeframe_id = id, description = description)
self._save(tf)
return tf
[docs] def broker(self, name, site):
"""
Save a broker on the db.
Args:
name (str): Name of the broker.
site (str): Website of the broker.
Return:
broker (alchemist_lib.database.broker.Broker): Map class instance.
"""
broker = Broker(broker_name = name, website = site)
self._save(broker)
return broker
[docs] def data_source(self, name, site, timeframes):
"""
Save a data_source on the db.
Args:
name (str): Name of the data source.
site (str): Website of the data source.
timeframes (list[alchemist_lib.database.timeframe.Timeframe]): List of supported timeframes.
Return:
ds (alchemist_lib.database.price_data_source.PriceDataSource): Map class instance.
"""
timeframes = utils.to_list(timeframes)
tfs = self.session.query(Timeframe).filter(Timeframe.timeframe_id.in_([t.timeframe_id for t in timeframes])).all()
ds = PriceDataSource(price_data_source_name = name, website = site)
ds.available_timeframes = tfs
self._save(ds)
return ds
[docs] def exchange(self, name, website, data_source, timetable, brokers):
"""
Save an exchange on the db.
Args:
name (str): Name of the exchange.
website (str): Website of the exchange.
data_source (alchemist_lib.database.price_data_source.PriceDataSource): PriceDataSource instance associated with this exchange. Specify how to get price informations.
timetable (alchemist_lib.database.timetable.Timetable): Timetable of this exchange.
brokers (list[alchemist_lib.database.broker.Broker]): Brokers that allow trading on this exchange.
Return:
exchange (alchemist_lib.database.exchange.Exchange): Map class instance.
"""
brokers = utils.to_list(brokers)
if data_source != None:
ds = self.session.query(PriceDataSource).filter(PriceDataSource.price_data_source_name == data_source.price_data_source_name).one()
else:
ds = data_source
if timetable != None:
tt = self.session.query(Timetable).filter(Timetable.open_hour == timetable.open_hour,
Timetable.open_minute == timetable.open_minute,
Timetable.close_hour == timetable.close_hour,
Timetable.close_minute == timetable.close_minute,
Timetable.timezone == timetable.timezone).one()
else:
tt = timetable
brks = self.session.query(Broker).filter(Broker.broker_name.in_([b.broker_name for b in brokers])).all()
exchange = Exchange(exchange_name = name, website = website)
exchange.price_data_source = ds
exchange.timetable = tt
exchange.brokers = brks
self._save(exchange)
return exchange
[docs] def asset(self, ticker, instrument_id, name, exchanges):
"""
Save an asset on the db.
Args:
ticker (str): Ticker code of the asset.
instrument_id (int): Financial instrument identifier.
name (str): Long name of the asset.
exchanges (list[alchemist_lib.database.asset.Asset]): Exchanges where this asset is tradable.
Return:
tt (alchemist_lib.database.asset.Asset): Map class instance.
"""
exchanges = utils.to_list(exchanges)
exchanges_already_saved = self.session.query(Exchange).join(Exchange, Asset.exchanges).filter(Asset.ticker == ticker, Asset.instrument_id == instrument_id).all()
exchs = self.session.query(Exchange).filter(Exchange.exchange_name.in_([e.exchange_name for e in exchanges])).all()
asset = Asset(ticker = ticker, instrument_id = instrument_id, name = name)
asset.exchanges = exchanges_already_saved + exchs
obj = asset
try:
self.session.add(obj)
self.session.commit()
except (IntegrityError, FlushError):
self.session.rollback()
asset = self.session.query(Asset).filter(Asset.ticker == obj.ticker).one()
asset.exchanges = exchanges_already_saved + exchs
try:
self.session.add(asset)
self.session.commit()
except (IntegrityError, FlushError):
self.session.rollback()
return asset