Source code for TradingMate

import os
import sys
import inspect
import logging
import datetime as dt

currentdir = os.path.dirname(os.path.abspath(
    inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)

from Model.DatabaseHandler import DatabaseHandler
from Utils.Utils import Callbacks, Actions, Messages
from UI.View import View
from Model.Portfolio import Portfolio
from Utils.ConfigurationManager import ConfigurationManager
from Utils.Utils import Utils


[docs]class TradingMate(): """ Main class that handles the interaction between the User Interface and the underlying business logic of the whole application """ LOG_FILEPATH = '{home}/.TradingMate/log/trading_mate_{timestamp}.log' def __init__(self): self.setup_logging() # Init the configuration manager self.configurationManager = ConfigurationManager() # Database handler self.db_handler = DatabaseHandler(self.configurationManager) # Init the portfolio self.portfolio = Portfolio("Portfolio1", self.configurationManager) # Init the view self.view = View() # Register callbacks self.register_callbacks() logging.info('TradingMate initialised')
[docs] def setup_logging(self): """ Setup the global logging settings """ time_str = dt.datetime.now().isoformat() time_suffix = time_str.replace(':', '_').replace('.', '_') log_filename = self.LOG_FILEPATH.replace( '{timestamp}', time_suffix).replace('{home}', Utils.get_home_path()) os.makedirs(os.path.dirname(log_filename), exist_ok=True) logging.basicConfig(filename=log_filename, level=logging.INFO, format="[%(asctime)s] %(levelname)s: %(message)s")
[docs] def register_callbacks(self): """ Register all the callback functions """ self.portfolio.set_callback( Callbacks.UPDATE_LIVE_PRICES, self.on_update_live_price) # Init the view self.view.set_callback( Callbacks.ON_CLOSE_VIEW_EVENT, self.on_close_view_event) self.view.set_callback( Callbacks.ON_MANUAL_REFRESH_EVENT, self.on_manual_refresh_event) self.view.set_callback( Callbacks.ON_NEW_TRADE_EVENT, self.on_new_trade_event) self.view.set_callback( Callbacks.ON_SET_AUTO_REFRESH_EVENT, self.on_set_auto_refresh) self.view.set_callback( Callbacks.ON_OPEN_LOG_FILE_EVENT, self.on_open_portfolio_event) self.view.set_callback( Callbacks.ON_SAVE_LOG_FILE_EVENT, self.on_save_portfolio_event) self.view.set_callback( Callbacks.ON_DELETE_LAST_TRADE_EVENT, self.on_delete_last_trade_event) self.view.set_callback( Callbacks.ON_SHOW_SETTINGS_EVENT, self.on_show_settings_event) self.view.set_callback( Callbacks.ON_SAVE_SETTINGS_EVENT, self.on_save_settings_event) logging.info('TradingMate - callbacks registered')
[docs] def start(self): """ Start the application """ logging.info('TradingMate start') # Read the configured database self.db_handler.read_data() # Start portfolio self.portfolio.start(self.db_handler.get_trades_list()) # Update the UI self._update_share_trading_view(updateHistory=True) # This should be the last instruction in this function self.view.start()
# Functions def _update_share_trading_view(self, updateHistory=False): """ Collect data from the model and update the view """ self.view.reset_view(updateHistory) # Update history table if required if updateHistory: logAsList = self.db_handler.get_trades_list()[ ::-1] # Reverse order self.view.update_share_trading_history_log(logAsList) # get the balances from the portfolio and update the view cash = self.portfolio.get_cash_available() holdingsValue = self.portfolio.get_holdings_value() totalValue = self.portfolio.get_total_value() pl = self.portfolio.get_portfolio_pl() pl_perc = self.portfolio.get_portfolio_pl_perc() holdingPL = self.portfolio.get_open_positions_pl() holdingPLPC = self.portfolio.get_open_positions_pl_perc() # Update the view validity = True for h in self.portfolio.get_holding_list(): self.view.update_share_trading_holding(h.get_symbol(), h.get_quantity(), h.get_open_price(), h.get_last_price(), h.get_cost(), h.get_value(), h.get_profit_loss(), h.get_profit_loss_perc(), h.get_last_price_valid()) validity = validity and h.get_last_price_valid() self.view.update_share_trading_portfolio_balances( cash, holdingsValue, totalValue, pl, pl_perc, holdingPL, holdingPLPC, validity) # EVENTS
[docs] def on_close_view_event(self): """ Callback function to handle close event of the user interface """ logging.info('UserInterface main window closed') self.portfolio.stop() self.db_handler.write_data() logging.info('TradingMate stop')
[docs] def on_manual_refresh_event(self): """ Callback function to handle refresh data request """ self.portfolio.on_manual_refresh_live_data()
[docs] def on_set_auto_refresh(self, enabled): """ Callback function to handle set/unset of auto refresh data """ self.portfolio.set_auto_refresh(enabled)
[docs] def on_update_live_price(self): """ Callback function to handle update of stock prices data """ self._update_share_trading_view()
[docs] def on_new_trade_event(self, new_trade): """ Callback function to handle new trade event """ logging.info('TradingMate - new trade event {}'.format(new_trade)) # Validate trade if not self.portfolio.is_trade_valid(new_trade): raise RuntimeError('Trade is invalid') # Update databse self.db_handler.add_trade(new_trade) # Reload portfolio self.portfolio.reload(self.db_handler.get_trades_list()) # Update the ui self._update_share_trading_view(updateHistory=True)
[docs] def on_delete_last_trade_event(self): """ Callback function to handle delete of last trade request """ logging.info('TradingMate - delete last trade request') # Remove trade from database self.db_handler.remove_last_trade() # Reload portfolio self.portfolio.reload(self.db_handler.get_trades_list()) # Update the UI self._update_share_trading_view(updateHistory=True)
[docs] def on_open_portfolio_event(self, filepath): """ Callback function to handle request to open a new portfolio file """ logging.info( 'TradingMate - open portfolio request from {}'.format(filepath)) # Read database from filepath self.db_handler.read_data(filepath) # Reload portfolio self.portfolio.reload(self.db_handler.get_trades_list()) # Update the UI self.view.reset_view(resetHistory=True) self._update_share_trading_view(updateHistory=True)
[docs] def on_save_portfolio_event(self, filepath): """ Callback function to handle request to save/export the portfolio """ logging.info( 'TradingMate - save portfolio request to {}'.format(filepath)) # Write data into the database self.db_handler.write_data(filepath=filepath)
[docs] def on_show_settings_event(self): """ Callback to handle request to show the settings panel """ return self.configurationManager.get_editable_config()
[docs] def on_save_settings_event(self, config): """ Callback to save edited settings """ self.configurationManager.save_settings(config) self.db_handler.read_data(self.configurationManager.get_trading_database_path()) self.portfolio.reload(self.db_handler.get_trades_list()) self._update_share_trading_view(updateHistory=True) logging.info('TradingMate - application reloaded')