Skip to content

Commit

Permalink
New trade time (#145)
Browse files Browse the repository at this point in the history
* Added time granularity to trades

* new trades with existing trade date are appended
  • Loading branch information
ilcardella committed Mar 14, 2020
1 parent 0062bba commit 753e83e
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 108 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support adding trades happened in the past
- Added popup menu in trades history treeview with option to add and remove trades
- Explore window to show information and details of single markets
- Time granularity to new trades

### Fixed
- Fixed bug where main window was hidden when closing app with unsaved changes
Expand Down
5 changes: 3 additions & 2 deletions src/Model/Portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ def add_trade(self, new_trade):
"""Add a new trade into the Portfolio"""
current_list = self._db_handler.get_trades_list()
# Build the list of trades happened before and after the new trade to validate
older_trades = [trade for trade in current_list if trade.date < new_trade.date]
newer_trades = [trade for trade in current_list if trade.date >= new_trade.date]
# If trade date match with existing trade, the new trade is appended after
older_trades = [trade for trade in current_list if trade.date <= new_trade.date]
newer_trades = [trade for trade in current_list if trade.date > new_trade.date]
# Build the new trade list inserting the new trade
new_trade_list = older_trades + [new_trade] + newer_trades
self._validate_trade_list(new_trade_list)
Expand Down
60 changes: 43 additions & 17 deletions src/UI/assets/gtk/add_trade_window_layout.glade
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
Expand All @@ -47,7 +47,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
Expand All @@ -59,7 +59,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
Expand All @@ -71,7 +71,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
Expand All @@ -83,7 +83,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
Expand All @@ -95,7 +95,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
Expand All @@ -107,7 +107,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
Expand All @@ -119,7 +119,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
Expand Down Expand Up @@ -150,7 +150,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
Expand All @@ -164,7 +164,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
Expand All @@ -179,7 +179,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
Expand All @@ -194,7 +194,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
Expand All @@ -209,7 +209,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
Expand All @@ -224,7 +224,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
Expand All @@ -239,7 +239,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">7</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
Expand All @@ -254,7 +254,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">8</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
Expand Down Expand Up @@ -300,7 +300,33 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">9</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="time_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="label" translatable="yes">Time:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="time_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="placeholder_text" translatable="yes">HH:MM</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
Expand Down
24 changes: 21 additions & 3 deletions src/UI/gtk/AddTradeWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
sys.path.insert(0, parentdir)

from Utils.Utils import Utils, Actions, Markets, Messages
from Utils.Trade import Trade
from Utils.Trade import Trade, DATETIME_FORMAT, TIME_FORMAT
from .MessageDialog import MessageDialog

# File paths
Expand All @@ -24,6 +24,7 @@
# GTK Widget IDs
ADD_TRADE_WINDOW = "add_trade_window"
DATE_CALENDAR = "date_calendar"
TIME_ENTRY = "time_entry"
ACTION_COMBO = "action_combo"
MARKET_COMBO = "market_combo"
SYMBOL_ENTRY = "symbol_entry"
Expand Down Expand Up @@ -51,6 +52,7 @@ def _load_UI(self, filepath):
top_level.set_transient_for(self._parent_window)
top_level.set_modal(True)
self._calendar = builder.get_object(DATE_CALENDAR)
self._time_entry = builder.get_object(TIME_ENTRY)
self._action_combo = builder.get_object(ACTION_COMBO)
self._market_combo = builder.get_object(MARKET_COMBO)
self._symbol_entry = builder.get_object(SYMBOL_ENTRY)
Expand All @@ -63,6 +65,7 @@ def _load_UI(self, filepath):
self._add_button = builder.get_object(ADD_BUTTON)
# Register callbacks
self._calendar.connect("day-selected", self._on_date_selected)
self._time_entry.connect("changed", self._on_entry_changed)
self._symbol_entry.connect("changed", self._on_entry_changed)
self._quantity_entry.connect("changed", self._on_entry_changed)
self._price_entry.connect("changed", self._on_entry_changed)
Expand All @@ -83,6 +86,10 @@ def _on_add_event(self, widget):
# Normalise widgets content with default values if necessary
year, month, day = self._calendar.get_date()
date_string = f"{day}/{month+1}/{year}"
time_string = self._time_entry.get_text()
date = datetime.datetime.strptime(
"{} {}".format(date_string, time_string), DATETIME_FORMAT
)
action = Actions[self._action_combo.get_active_text()]
quantity = float(
self._quantity_entry.get_text()
Expand All @@ -105,7 +112,7 @@ def _on_add_event(self, widget):
)
notes = str(self._notes_entry.get_text())
# Create a Trade instance from the widgets content
t = Trade(date_string, action, quantity, market, price, fee, sdr, notes)
t = Trade(date, action, quantity, market, price, fee, sdr, notes)
# Call server and handle errors
try:
self._client.new_trade_event(t, self._portfolio_id)
Expand Down Expand Up @@ -196,6 +203,8 @@ def _load_static_content(self):
now = datetime.datetime.now()
self._calendar.select_month(now.month - 1, now.year)
self._calendar.select_day(0) # Clear day selection
# Time
self._time_entry.set_text("00:00")
# Combo action
self._action_combo.remove_all()
for a in Actions:
Expand All @@ -206,9 +215,10 @@ def _load_static_content(self):
self._market_combo.append_text(m.name)

def _clear_content(self, clear_calendar=True):
# Clear day selection in calendar
# Clear day selection in calendar and time
if clear_calendar:
self._calendar.select_day(0)
self._time_entry.set_text("00:00")
# Reset entries
self._symbol_entry.set_text("")
self._quantity_entry.set_text("")
Expand All @@ -222,6 +232,7 @@ def _check_data_validity(self):
valid = all(
[
0 < date < 32,
self._is_time_valid(self._time_entry.get_text()),
not self._symbol_entry.get_sensitive()
or self._is_string_valid(self._symbol_entry.get_text()),
not self._quantity_entry.get_sensitive()
Expand Down Expand Up @@ -254,6 +265,13 @@ def _is_float_valid(self, string_value, zero_ok=False):
except:
return False

def _is_time_valid(self, string):
try:
date = datetime.datetime.strptime(string, TIME_FORMAT)
return True
except:
return False

### Public API

def show(self):
Expand Down
14 changes: 8 additions & 6 deletions src/Utils/Trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@

from Utils.Utils import Actions

TIME_FORMAT = "%H:%M"
DATE_FORMAT = "%d/%m/%Y"
DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT


class Trade:
def __init__(
self, date_string, action, quantity, symbol, price, fee, sdr, notes, id=None
):
def __init__(self, date, action, quantity, symbol, price, fee, sdr, notes, id=None):
try:
self.date = datetime.datetime.strptime(date_string, "%d/%m/%Y")
self.date = date
if not isinstance(action, Actions):
raise ValueError("Invalid action")
self.action = action
Expand All @@ -38,7 +40,7 @@ def __init__(
def to_dict(self):
return {
"id": self.id,
"date": self.date.strftime("%d/%m/%Y"),
"date": self.date.strftime(DATETIME_FORMAT),
"action": self.action.name,
"quantity": self.quantity,
"symbol": self.symbol,
Expand Down Expand Up @@ -71,7 +73,7 @@ def from_dict(item):
raise ValueError("item not well formatted")

return Trade(
item["date"],
datetime.datetime.strptime(item["date"], DATETIME_FORMAT),
Actions[item["action"]],
item["quantity"],
item["symbol"],
Expand Down
1 change: 0 additions & 1 deletion test/test_configuration_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
sys.path.insert(0, "{}/src".format(parentdir))

from Utils.ConfigurationManager import ConfigurationManager
from Utils.Trade import Trade


@pytest.fixture
Expand Down

0 comments on commit 753e83e

Please sign in to comment.