mirror of
https://github.com/RolandWH/SIPPCompare.git
synced 2025-03-14 13:51:36 +00:00
User-defined fee structure (except tiered) and file saving
This commit is contained in:
parent
abeaec2f8c
commit
c20e1e9d09
@ -48,6 +48,19 @@
|
|||||||
<string>OK</string>
|
<string>OK</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QPushButton" name="res_save_but">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>240</x>
|
||||||
|
<y>270</y>
|
||||||
|
<width>75</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -6,65 +6,143 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>771</width>
|
<width>484</width>
|
||||||
<height>502</height>
|
<height>290</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Platform Editor</string>
|
<string>Platform Editor</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QScrollArea" name="scrollArea">
|
<widget class="QWidget" name="gridLayoutWidget">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>180</x>
|
<x>10</x>
|
||||||
<y>130</y>
|
<y>10</y>
|
||||||
<width>331</width>
|
<width>461</width>
|
||||||
<height>191</height>
|
<height>191</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="widgetResizable">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<bool>true</bool>
|
<property name="leftMargin">
|
||||||
</property>
|
<number>6</number>
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>329</width>
|
|
||||||
<height>189</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
<widget class="QListWidget" name="listWidget">
|
<property name="topMargin">
|
||||||
<property name="geometry">
|
<number>6</number>
|
||||||
<rect>
|
</property>
|
||||||
<x>10</x>
|
<property name="rightMargin">
|
||||||
<y>10</y>
|
<number>6</number>
|
||||||
<width>311</width>
|
</property>
|
||||||
<height>141</height>
|
<property name="bottomMargin">
|
||||||
</rect>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<property name="horizontalSpacing">
|
||||||
|
<number>15</number>
|
||||||
|
</property>
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="share_plat_fee_lab">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>up to</string>
|
<string>Share platform fee</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
<widget class="QPushButton" name="pushButton">
|
<item row="4" column="2">
|
||||||
<property name="geometry">
|
<widget class="QLineEdit" name="share_deal_fee_box"/>
|
||||||
<rect>
|
</item>
|
||||||
<x>210</x>
|
<item row="3" column="2">
|
||||||
<y>160</y>
|
<widget class="QLineEdit" name="share_plat_max_fee_box"/>
|
||||||
<width>111</width>
|
</item>
|
||||||
<height>24</height>
|
<item row="0" column="0" colspan="2">
|
||||||
</rect>
|
<widget class="QLabel" name="fund_deal_fee_lab">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="text">
|
<string>Fund dealing fee</string>
|
||||||
<string>PushButton</string>
|
</property>
|
||||||
</property>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
</widget>
|
<item row="0" column="2">
|
||||||
|
<widget class="QLineEdit" name="fund_deal_fee_box"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLineEdit" name="share_plat_fee_box"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="share_plat_max_fee_lab">
|
||||||
|
<property name="text">
|
||||||
|
<string>Share platform fee cap</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="2">
|
||||||
|
<widget class="QLineEdit" name="share_deal_reduce_amount_box"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="share_deal_fee_lab">
|
||||||
|
<property name="text">
|
||||||
|
<string>Share dealing fee</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="share_deal_reduce_amount_lab">
|
||||||
|
<property name="text">
|
||||||
|
<string>Share dealing fee discount</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="2">
|
||||||
|
<widget class="QLineEdit" name="share_deal_reduce_trades_box"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="share_deal_reduce_trades_lab">
|
||||||
|
<property name="text">
|
||||||
|
<string>Share dealing discount # of trades</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="save_but">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>290</x>
|
||||||
|
<y>260</y>
|
||||||
|
<width>191</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>fund_deal_fee_box</tabstop>
|
||||||
|
<tabstop>share_plat_fee_box</tabstop>
|
||||||
|
<tabstop>share_plat_max_fee_box</tabstop>
|
||||||
|
<tabstop>share_deal_fee_box</tabstop>
|
||||||
|
<tabstop>share_deal_reduce_trades_box</tabstop>
|
||||||
|
<tabstop>share_deal_reduce_amount_box</tabstop>
|
||||||
|
<tabstop>save_but</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>save_but</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>PlatformEdit</receiver>
|
||||||
|
<slot>close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>445</x>
|
||||||
|
<y>211</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>275</x>
|
||||||
|
<y>117</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QApplication
|
|
||||||
import main_window
|
import main_window
|
||||||
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
window = main_window.SIPPCompare()
|
window = main_window.SIPPCompare()
|
||||||
window.show()
|
window.show()
|
||||||
|
window.show_platform_edit()
|
||||||
app.exec()
|
app.exec()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from PyQt6.QtWidgets import QMainWindow
|
from PyQt6.QtWidgets import QMainWindow
|
||||||
from PyQt6 import uic
|
from PyQt6 import uic
|
||||||
|
|
||||||
import platform_edit
|
import platform_edit
|
||||||
import output_window
|
import output_window
|
||||||
|
|
||||||
@ -10,41 +11,50 @@ class SIPPCompare(QMainWindow):
|
|||||||
uic.loadUi("gui/main_gui.ui", self)
|
uic.loadUi("gui/main_gui.ui", self)
|
||||||
|
|
||||||
# Define class variables
|
# Define class variables
|
||||||
self.tiered_fees = [
|
self.fund_plat_fee = 0.0
|
||||||
[0, 250000, 1000000, 2000000],
|
self.fund_deal_fee = 0.0
|
||||||
[0, 0.25, 0.1, 0.05]
|
self.share_plat_fee = 0.0
|
||||||
]
|
self.share_plat_max_fee = 0.0
|
||||||
self.fund_deal_fee = 1.5
|
self.share_deal_fee = 0.0
|
||||||
self.share_plat_fee = 0.0025
|
self.share_deal_reduce_trades = 0.0
|
||||||
self.share_plat_max_fee = 3.5
|
self.share_deal_reduce_amount = 0.0
|
||||||
self.share_deal_fee = 5
|
|
||||||
self.share_deal_reduce_trades = 10
|
self.fund_plat_fees = 0.0
|
||||||
self.share_deal_reduce_amount = 3.5
|
self.fund_deal_fees = 0.0
|
||||||
|
self.share_plat_fees = 0.0
|
||||||
|
self.share_deal_fees = 0.0
|
||||||
|
|
||||||
self.result = None
|
|
||||||
self.platform_win = None
|
self.platform_win = None
|
||||||
self.output_win = None
|
self.output_win = output_window.OutputWindow()
|
||||||
|
|
||||||
# Handle events
|
# Handle events
|
||||||
self.calc_but.clicked.connect(self.calculate_fee)
|
self.calc_but.clicked.connect(self.calculate_fees)
|
||||||
self.actionEdit_Platforms.triggered.connect(self.show_platform_edit)
|
self.actionEdit_Platforms.triggered.connect(self.show_platform_edit)
|
||||||
self.mix_slider.valueChanged.connect(self.update_slider_lab)
|
self.mix_slider.valueChanged.connect(self.update_slider_lab)
|
||||||
|
|
||||||
# Display slider position as mix between two nums (funds/shares)
|
# Display slider position as mix between two nums (funds/shares)
|
||||||
def update_slider_lab(self):
|
def update_slider_lab(self):
|
||||||
slider_val = self.mix_slider.value()
|
slider_val = self.mix_slider.value()
|
||||||
self.mix_lab.setText(f"Investment mix (funds {slider_val}% / shares {100 - slider_val}%)")
|
mix_lab_str = f"Investment mix (funds {slider_val}% / shares {100 - slider_val}%)"
|
||||||
#mix_percent_lab_str = f"{slider_val}% / {100 - slider_val}%"
|
self.mix_lab.setText(mix_lab_str)
|
||||||
#self.mix_percent_lab.setText(mix_percent_lab_str)
|
|
||||||
|
def init_variables(self):
|
||||||
|
self.fund_plat_fee = self.platform_win.get_fund_plat_fee()
|
||||||
|
self.fund_deal_fee = self.platform_win.get_fund_deal_fee()
|
||||||
|
self.share_plat_fee = self.platform_win.get_share_plat_fee()
|
||||||
|
self.share_plat_max_fee = self.platform_win.get_share_plat_max_fee()
|
||||||
|
self.share_deal_fee = self.platform_win.get_share_deal_fee()
|
||||||
|
self.share_deal_reduce_trades = self.platform_win.get_share_deal_reduce_trades()
|
||||||
|
self.share_deal_reduce_amount = self.platform_win.get_share_deal_reduce_amount()
|
||||||
|
|
||||||
# Calculate fees
|
# Calculate fees
|
||||||
def calculate_fee(self):
|
def calculate_fees(self):
|
||||||
|
self.init_variables()
|
||||||
value_num = float(self.value_input.text()[1:])
|
value_num = float(self.value_input.text()[1:])
|
||||||
slider_val = self.mix_slider.value()
|
slider_val = self.mix_slider.value()
|
||||||
funds_value = (slider_val / 100) * value_num
|
funds_value = (slider_val / 100) * value_num
|
||||||
fund_trades_num = int(self.fund_trades_combo.currentText())
|
fund_trades_num = int(self.fund_trades_combo.currentText())
|
||||||
fund_deal_fees = fund_trades_num * self.fund_deal_fee
|
self.fund_deal_fees = fund_trades_num * self.fund_deal_fee
|
||||||
fund_plat_fees = 0
|
|
||||||
remaining = funds_value
|
remaining = funds_value
|
||||||
|
|
||||||
for i in range(1, len(self.tiered_fees[0])):
|
for i in range(1, len(self.tiered_fees[0])):
|
||||||
@ -54,33 +64,31 @@ class SIPPCompare(QMainWindow):
|
|||||||
gap = (band - prev_band)
|
gap = (band - prev_band)
|
||||||
|
|
||||||
if remaining > gap:
|
if remaining > gap:
|
||||||
fund_plat_fees += gap * (fee / 100)
|
self.fund_plat_fees += gap * (fee / 100)
|
||||||
remaining -= gap
|
remaining -= gap
|
||||||
else:
|
else:
|
||||||
fund_plat_fees += remaining * (fee / 100)
|
self.fund_plat_fees += remaining * (fee / 100)
|
||||||
break
|
break
|
||||||
|
|
||||||
shares_value = (1 - (slider_val / 100)) * value_num
|
shares_value = (1 - (slider_val / 100)) * value_num
|
||||||
if (self.share_plat_fee * shares_value / 12) > self.share_plat_max_fee:
|
if (self.share_plat_fee * shares_value / 12) > self.share_plat_max_fee:
|
||||||
share_plat_fees = self.share_plat_max_fee * 12
|
self.share_plat_fees = self.share_plat_max_fee * 12
|
||||||
else:
|
else:
|
||||||
share_plat_fees = self.share_plat_fee * shares_value
|
self.share_plat_fees = self.share_plat_fee * shares_value
|
||||||
|
|
||||||
share_trades_num = int(self.share_trades_combo.currentText())
|
share_trades_num = int(self.share_trades_combo.currentText())
|
||||||
if (share_trades_num / 12) >= self.share_deal_reduce_trades:
|
if (share_trades_num / 12) >= self.share_deal_reduce_trades:
|
||||||
share_deal_fees = self.share_deal_reduce_amount * share_trades_num
|
self.share_deal_fees = self.share_deal_reduce_amount * share_trades_num
|
||||||
else:
|
else:
|
||||||
share_deal_fees = self.share_deal_fee * share_trades_num
|
self.share_deal_fees = self.share_deal_fee * share_trades_num
|
||||||
|
|
||||||
self.show_output_win(fund_plat_fees, fund_deal_fees, share_plat_fees, share_deal_fees)
|
self.show_output_win()
|
||||||
|
|
||||||
# Show the output window - this func is called from calculate_fee()
|
# Show the output window - this func is called from calculate_fee()
|
||||||
def show_output_win(self, fund_plat_fees, fund_deal_fees, share_plat_fees, share_deal_fees):
|
def show_output_win(self):
|
||||||
# Check window isn't already open
|
|
||||||
if self.output_win is None:
|
|
||||||
self.output_win = output_window.OutputWindow()
|
|
||||||
# Refresh the results when new fees are calculated
|
# Refresh the results when new fees are calculated
|
||||||
self.output_win.display_output(fund_plat_fees, fund_deal_fees, share_plat_fees, share_deal_fees)
|
self.output_win.display_output(self.fund_plat_fees, self.fund_deal_fees,
|
||||||
|
self.share_plat_fees, self.share_deal_fees)
|
||||||
self.output_win.show()
|
self.output_win.show()
|
||||||
|
|
||||||
# Show the platform editor window (currently useless)
|
# Show the platform editor window (currently useless)
|
||||||
|
@ -1,28 +1,47 @@
|
|||||||
from PyQt6.QtWidgets import QWidget
|
from PyQt6.QtWidgets import QWidget
|
||||||
from PyQt6 import uic
|
from PyQt6 import uic
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
import platform_edit
|
||||||
|
|
||||||
|
|
||||||
class OutputWindow(QWidget):
|
class OutputWindow(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
uic.loadUi("gui/output_window.ui", self)
|
uic.loadUi("gui/output_window.ui", self)
|
||||||
|
|
||||||
|
self.res_save_but.clicked.connect(self.save_results)
|
||||||
|
self.results_str = ""
|
||||||
|
|
||||||
|
def save_results(self):
|
||||||
|
cur_time = datetime.datetime.now()
|
||||||
|
if not os.path.exists("output"):
|
||||||
|
os.makedirs("output")
|
||||||
|
filename_str = (f"output/{cur_time.year}-{cur_time.month}-{cur_time.day}"
|
||||||
|
f".{cur_time.hour}-{cur_time.minute}-{cur_time.second}.txt")
|
||||||
|
output_file = open(filename_str, "wt")
|
||||||
|
output_file.write(self.results_str)
|
||||||
|
|
||||||
|
|
||||||
def display_output(self, fund_plat_fees: float, fund_deal_fees: float,
|
def display_output(self, fund_plat_fees: float, fund_deal_fees: float,
|
||||||
share_plat_fees: float, share_deal_fees: float):
|
share_plat_fees: float, share_deal_fees: float):
|
||||||
results_str = "Fees breakdown:"
|
self.results_str = "Fees breakdown:"
|
||||||
|
|
||||||
results_str += "\n\nPlatform fees:"
|
self.results_str += "\n\nPlatform fees:"
|
||||||
results_str += f"\n\tFund platform fees: £{round(fund_plat_fees, 2):.2f}"
|
self.results_str += f"\n\tFund platform fees: £{round(fund_plat_fees, 2):.2f}"
|
||||||
results_str += f"\n\tShare platform fees: £{round(share_plat_fees, 2):.2f}"
|
self.results_str += f"\n\tShare platform fees: £{round(share_plat_fees, 2):.2f}"
|
||||||
total_plat_fees = fund_plat_fees + share_plat_fees
|
total_plat_fees = fund_plat_fees + share_plat_fees
|
||||||
results_str += f"\n\tTotal platform fees: £{round(total_plat_fees, 2):.2f}"
|
self.results_str += f"\n\tTotal platform fees: £{round(total_plat_fees, 2):.2f}"
|
||||||
|
|
||||||
results_str += "\n\nDealing fees:"
|
self.results_str += "\n\nDealing fees:"
|
||||||
results_str += f"\n\tFund dealing fees: £{round(fund_deal_fees, 2):.2f}"
|
self.results_str += f"\n\tFund dealing fees: £{round(fund_deal_fees, 2):.2f}"
|
||||||
results_str += f"\n\tShare dealing fees: £{round(share_deal_fees, 2):.2f}"
|
self.results_str += f"\n\tShare dealing fees: £{round(share_deal_fees, 2):.2f}"
|
||||||
total_deal_fees = fund_deal_fees + share_deal_fees
|
total_deal_fees = fund_deal_fees + share_deal_fees
|
||||||
results_str += f"\n\tTotal dealing fees: £{round(total_deal_fees, 2):.2f}"
|
self.results_str += f"\n\tTotal dealing fees: £{round(total_deal_fees, 2):.2f}"
|
||||||
|
|
||||||
total_fees = total_plat_fees + total_deal_fees
|
total_fees = total_plat_fees + total_deal_fees
|
||||||
results_str += f"\n\nTotal fees: £{round(total_fees, 2):.2f}"
|
self.results_str += f"\n\nTotal fees: £{round(total_fees, 2):.2f}"
|
||||||
|
|
||||||
self.output.setText(results_str)
|
self.output.setText(self.results_str)
|
||||||
|
@ -1,7 +1,50 @@
|
|||||||
from PyQt6.QtWidgets import QWidget
|
from PyQt6.QtWidgets import QWidget
|
||||||
from PyQt6 import uic
|
from PyQt6 import uic
|
||||||
|
|
||||||
|
|
||||||
class PlatformEdit(QWidget):
|
class PlatformEdit(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
uic.loadUi("gui/platform_edit.ui", self)
|
uic.loadUi("gui/platform_edit.ui", self)
|
||||||
|
|
||||||
|
self.fund_plat_fee = [
|
||||||
|
[0, 250000, 1000000, 2000000],
|
||||||
|
[0, 0.25, 0.1, 0.05]
|
||||||
|
]
|
||||||
|
self.fund_deal_fee = 0.0
|
||||||
|
self.share_plat_fee = 0.0
|
||||||
|
self.share_plat_max_fee = 0.0
|
||||||
|
self.share_deal_fee = 0.0
|
||||||
|
self.share_deal_reduce_trades = 0.0
|
||||||
|
self.share_deal_reduce_amount = 0.0
|
||||||
|
|
||||||
|
self.save_but.clicked.connect(self.init_variables)
|
||||||
|
|
||||||
|
def init_variables(self):
|
||||||
|
self.fund_deal_fee = float(self.fund_deal_fee_box.text())
|
||||||
|
self.share_plat_fee = float(self.share_plat_fee_box.text()) / 100
|
||||||
|
self.share_plat_max_fee = float(self.share_plat_max_fee_box.text())
|
||||||
|
self.share_deal_fee = float(self.share_deal_fee_box.text())
|
||||||
|
self.share_deal_reduce_trades = float(self.share_deal_reduce_trades_box.text())
|
||||||
|
self.share_deal_reduce_amount = float(self.share_deal_reduce_amount_box.text())
|
||||||
|
|
||||||
|
def get_fund_plat_fee(self):
|
||||||
|
return self.fund_plat_fee
|
||||||
|
|
||||||
|
def get_fund_deal_fee(self):
|
||||||
|
return self.fund_deal_fee
|
||||||
|
|
||||||
|
def get_share_plat_fee(self):
|
||||||
|
return self.share_plat_fee
|
||||||
|
|
||||||
|
def get_share_plat_max_fee(self):
|
||||||
|
return self.share_plat_max_fee
|
||||||
|
|
||||||
|
def get_share_deal_fee(self):
|
||||||
|
return self.share_deal_fee
|
||||||
|
|
||||||
|
def get_share_deal_reduce_trades(self):
|
||||||
|
return self.share_deal_reduce_trades
|
||||||
|
|
||||||
|
def get_share_deal_reduce_amount(self):
|
||||||
|
return self.share_deal_reduce_amount
|
||||||
|
Loading…
x
Reference in New Issue
Block a user