Skip to content

Commit

Permalink
Merge pull request #16 from ilcardella/refactor-config-json
Browse files Browse the repository at this point in the history
Converted xml config to json format
  • Loading branch information
ilcardella committed Jan 28, 2019
2 parents b26e5c4 + 76f8e98 commit ae3acc5
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 93 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,14 @@ sudo chmod 600 .credentials
The `config.json` file is in the `config` folder and it contains several configurable parameter to personalise how TradingMate works.
These are the descriptions of each parameter:

- **trading_log_path**: The absolute path of the trading log where the history
- **general/trading_log_path**: The absolute path of the trading log where the history
of your trades are saved
- **general/debug_log**: Activate the debug logging level
- **general/enable_file_log**: Activate logging on a file
- **general/log_filepath**: File path of the logging file (if active)
- **general/credentials_filepath**: File path of the .credentials file
- **alpha_vantage/api_base_uri**: Base URI of AlphaVantage API
- **alpha_vantage/polling_period_sec**: The polling period to query AlphaVantage for stock prices

# Run

Expand Down
10 changes: 9 additions & 1 deletion config/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
{
"general": {
"trading_log_path": "/home/alberto/Dropbox/Documents/Trading/trading_log.json"
"debug_log": false,
"enable_file_log": false,
"log_filepath": "{home}/.TradingMate/log/trading_mate_{timestamp}.log",
"trading_log_path": "/home/alberto/Dropbox/Documents/Trading/trading_log.json",
"credentials_filepath": "../data/.credentials"
},
"alpha_vantage": {
"api_base_uri": "https://www.alphavantage.co/query",
"polling_period_sec": 30
}
}
10 changes: 0 additions & 10 deletions data/config.xml

This file was deleted.

28 changes: 13 additions & 15 deletions src/Model/Model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,46 @@
import inspect
import xml.etree.ElementTree as ET
from xml.dom import minidom
import threading
import time
import urllib.request
import json
import logging

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

from .StockPriceGetter import StockPriceGetter
from .Portfolio import Portfolio
from Utils.Utils import Messages, Actions, Callbacks
from Utils.ConfigurationManager import ConfigurationManager
from Utils.TaskThread import TaskThread
from Utils.Utils import Messages, Actions, Callbacks
from .Portfolio import Portfolio
from .StockPriceGetter import StockPriceGetter


class Model():

def __init__(self, configurationManager):
self.configurationManager = configurationManager
self._read_configuration()
def __init__(self, config):
self._read_configuration(config)
self._read_database(self.dbFilePath)
self.callbacks = {} # DataStruct containing the callbacks
self.livePricesThread = StockPriceGetter(
self.configurationManager, self.on_new_price_data, self.webPollingPeriod)
self.livePricesThread = StockPriceGetter(config,
self.on_new_price_data, self.webPollingPeriod)
self.portfolio = Portfolio("Portfolio1")

# INTERNAL FUNCTIONS

def set_callback(self, id, callback):
self.callbacks[id] = callback

def _read_configuration(self):
self.dbFilePath = self.configurationManager.get_trading_database_path()
self.webPollingPeriod = self.configurationManager.get_alpha_vantage_polling_period()
def _read_configuration(self, config):
self.dbFilePath = config.get_trading_database_path()
self.webPollingPeriod = config.get_alpha_vantage_polling_period()

def _read_database(self, filepath):
try:
tradingLogXMLTree = ET.parse(filepath)
self.log = tradingLogXMLTree.getroot()
except Exception as e:
print("Model: Error reading database! {0}".format(e))
logging.error("Model: Error reading database: {}".format(e))
self.log = ET.Element("log")

def _update_portfolio(self):
Expand Down
19 changes: 8 additions & 11 deletions src/Model/StockPriceGetter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from Utils.TaskThread import TaskThread
import os
import sys
import inspect
Expand All @@ -10,24 +9,22 @@
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)

from Utils.TaskThread import TaskThread
from Utils.ConfigurationManager import ConfigurationManager


class StockPriceGetter(TaskThread):

def __init__(self, configurationManager, onNewPriceDataCallback, updatePeriod):
def __init__(self, config, onNewPriceDataCallback, updatePeriod):
TaskThread.__init__(self, updatePeriod)
self.onNewPriceDataCallback = onNewPriceDataCallback
self.configurationManager = configurationManager
self._read_configuration()
self._read_configuration(config)
self.lastData = {}
self.symbolList = []

def _read_configuration(self):
try:
self.alphaVantageAPIKey = self.configurationManager.get_alpha_vantage_api_key()
self.alphaVantageBaseURL = self.configurationManager.get_alpha_vantage_base_url()
except Exception as e:
print("LivePricesWebThread: _read_configuration() {0}".format(e))
sys.exit(1)
def _read_configuration(self, config):
self.alphaVantageAPIKey = config.get_alpha_vantage_api_key()
self.alphaVantageBaseURL = config.get_alpha_vantage_base_url()

def task(self):
priceDict = {}
Expand Down
84 changes: 61 additions & 23 deletions src/TradingMate.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,88 @@
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.Model import Model
from Utils.Utils import Callbacks, Actions, Messages
from UI.View import View
from Model.Portfolio import Portfolio
from Utils.ConfigurationManager import ConfigurationManager
from Model.Portfolio import Portfolio
from UI.View import View
from Utils.Utils import Callbacks, Actions, Messages
from Model.Model import Model


class TradingMate():

def __init__(self):
# Init the configuration manager
self.configurationManager = ConfigurationManager()
# Setup the logging
self.setup_logging()
# Init the model
self.model = Model(self.configurationManager)
self.model.set_callback(Callbacks.UPDATE_LIVE_PRICES, self.on_update_live_price)
self.model.set_callback(
Callbacks.UPDATE_LIVE_PRICES, self.on_update_live_price)
# Init the view
self.view = 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_log_file_event)
self.view.set_callback(Callbacks.ON_SAVE_LOG_FILE_EVENT, self.on_save_log_file_event)
self.view.set_callback(Callbacks.ON_DELETE_LAST_TRADE_EVENT, self.on_delete_last_trade_event)
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_log_file_event)
self.view.set_callback(
Callbacks.ON_SAVE_LOG_FILE_EVENT, self.on_save_log_file_event)
self.view.set_callback(
Callbacks.ON_DELETE_LAST_TRADE_EVENT, self.on_delete_last_trade_event)

def setup_logging(self):
"""
Setup the global logging settings
"""
# Define the global logging settings
debugLevel = logging.DEBUG if self.configurationManager.get_debug_log_active() else logging.INFO
# If enabled define log file filename with current timestamp
if self.configurationManager.get_enable_file_log():
log_filename = self.configurationManager.get_log_filepath()
time_str = dt.datetime.now().isoformat()
time_suffix = time_str.replace(':', '_').replace('.', '_')
home = str(Path.home())
log_filename = log_filename.replace(
'{timestamp}', time_suffix).replace('{home}', home)
os.makedirs(os.path.dirname(log_filename), exist_ok=True)
logging.basicConfig(filename=log_filename,
level=debugLevel,
format="[%(asctime)s] %(levelname)s: %(message)s")
else:
logging.basicConfig(level=debugLevel,
format="[%(asctime)s] %(levelname)s: %(message)s")

def start(self):
self.model.start()
self._update_share_trading_view(updateHistory=True)
self.view.start() # This should be the last instruction in this function
self.view.start() # This should be the last instruction in this function

# Functions

def _check_new_trade_validity(self, newTrade):
result = {"success":True,"message":"ok"}
result = {"success": True, "message": "ok"}
portfolio = self.model.get_portfolio()

if newTrade["action"] == Actions.WITHDRAW.name:
if newTrade["amount"] > portfolio.get_cash_available():
result["success"] = False
result["message"] = Messages.INSUF_FUNDING.value
elif newTrade["action"] == Actions.BUY.name:
cost = (newTrade["price"] * newTrade["amount"]) / 100 # in £
cost = (newTrade["price"] * newTrade["amount"]) / 100 # in £
fee = newTrade["fee"]
tax = (newTrade["stamp_duty"] * cost) / 100
totalCost = cost + fee + tax
Expand All @@ -67,7 +103,7 @@ def _update_share_trading_view(self, updateHistory=False):
self.view.set_db_filepath(filepath)
# Update history table if required
if updateHistory:
logAsList = self.model.get_log_as_list()[::-1] # Reverse order
logAsList = self.model.get_log_as_list()[::-1] # Reverse order
self.view.update_share_trading_history_log(logAsList)
# Compute the current holding profits and balances
portfolio = self.model.get_portfolio()
Expand All @@ -82,10 +118,11 @@ def _update_share_trading_view(self, updateHistory=False):
# Update the view
validity = True
for h in portfolio.get_holding_list():
self.view.update_share_trading_holding(h.get_symbol(), h.get_amount(), 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())
self.view.update_share_trading_holding(h.get_symbol(), h.get_amount(), 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)
self.view.update_share_trading_portfolio_balances(
cash, holdingsValue, totalValue, pl, pl_perc, holdingPL, holdingPLPC, validity)

# EVENTS

Expand All @@ -99,15 +136,16 @@ def on_set_auto_refresh(self, enabled):
self.model.set_auto_refresh(enabled)

def on_update_live_price(self):
self._update_share_trading_view()
self._update_share_trading_view()

def on_new_trade_event(self, newTrade):
result = {"success":True,"message":"ok"}
result = {"success": True, "message": "ok"}

valResult = self._check_new_trade_validity(newTrade)

if valResult["success"]:
modelResult = self.model.add_new_trade(newTrade) # Update the model
modelResult = self.model.add_new_trade(
newTrade) # Update the model
if modelResult["success"]:
self._update_share_trading_view(updateHistory=True)
else:
Expand All @@ -127,7 +165,7 @@ def on_save_log_file_event(self, filepath):
return self.model.save_log_file(filepath)

def on_delete_last_trade_event(self):
result = {"success":True,"message":"ok"}
result = {"success": True, "message": "ok"}
result = self.model.delete_last_trade()
if result["success"]:
self._update_share_trading_view(updateHistory=True)
Expand Down

0 comments on commit ae3acc5

Please sign in to comment.