I am coming from C# and I am learning how to use Python more seriously.
So I decided to try a little side project to help me see how much I earn (or lose) from my trades on the stock market.
I would like some advice about how I structured my project, in C# I am used to put each class in its own file, but I read that in Python we work with module, so I put several classes in the trades.py module. But does it make sense to put the trade importer in the same module as the calculator?
Here is a screenshot of my project hierarchy so far:
and a description of the files:
trades.py
import calculator.trades as t
from enum import Enum
import numpy as np
class TradeType(Enum):
Buy = 1
Sell = -1
class Trade:
def __init__(self, id, trade_date, type, quantity, price, currency_id, company_id, account_id):
self.id = id
self.type = type
self.account_id = account_id
self.company_id = company_id
self.currency_id = currency_id
self.trade_date = trade_date
self.quantity = quantity
self.price = price
class TradePnlCalculator:
def compute_pnl(self, trades):
signed_quantities = np.array([-1 * t.type.value * t.quantity for t in trades])
prices = np.array([t.price for t in trades])
return np.dot(signed_quantities, prices)
class TradeImporter:
def load_trades(self):
# TODO Read the trades from a file
return []
test_tradePnlCalculator.py
from unittest import TestCase
from calculator.trades import Trade, TradeType, TradePnlCalculator
import datetime
class TestTradePnlCalculator(TestCase):
def setUp(self):
now = datetime.datetime.now()
self.trade1 = Trade(1, trade_date=now, type=TradeType.Buy, quantity=100,
price=34.5, currency_id=1, company_id=1, account_id=1)
self.trade2 = Trade(2, trade_date=now, type=TradeType.Sell, quantity=100,
price=37.4, currency_id=1, company_id=1, account_id=1)
self.calculator = TradePnlCalculator()
def test_compute_pnl_returns_zero_when_there_is_no_trades(self):
self.assertEquals(0, self.calculator.compute_pnl([]))
def test_compute_pnl_returns_negative_flow_for_single_buy_trade(self):
self.assertEquals(-3450, self.calculator.compute_pnl([self.trade1]))
def test_compute_pnl_returns_positive_flow_for_single_sell_trade(self):
self.assertEquals(3740, self.calculator.compute_pnl([self.trade2]))
def test_compute_pnl_returns_correct_value_for_cancelling_trades(self):
self.assertEquals(3740-3450, self.calculator.compute_pnl([self.trade1, self.trade2]))
run.py
importer = t.TradeImporter()
trades = importer.load_trades()
calculator = t.TradePnlCalculator()
pnl = calculator.compute_pnl(trades)
print('The profit for the trades is {} euros'.format(pnl))