Spaces:
Running
Running
Upload 17 files
Browse files- app.py +30 -12
- interface/about_interface.py +4 -3
- interface/dollar_cost_averaging_interface.py +4 -1
- interface/rebalancing_interface.py +4 -0
- interface/retirement_planning_interface.py +4 -2
- interface/share_price_trend_interface.py +5 -3
- modules/rebalancing.py +1 -1
- modules/utils.py +1 -1
- style.css +16 -0
app.py
CHANGED
@@ -4,35 +4,40 @@ from interface.rebalancing_interface import (
|
|
4 |
output as rebalancing_output,
|
5 |
update_output as rebalancing_update_output,
|
6 |
examples as rebalancing_examples,
|
7 |
-
component_rows as rebalancing_component_rows
|
|
|
8 |
)
|
9 |
from interface.share_price_trend_interface import (
|
10 |
input as share_price_trend_inputs,
|
11 |
output as share_price_trend_output,
|
12 |
update_output as share_price_trend_update_output,
|
13 |
examples as share_price_trend_examples,
|
14 |
-
component_rows as share_price_trend_component_rows
|
|
|
15 |
)
|
16 |
from interface.dollar_cost_averaging_interface import (
|
17 |
input as dollar_cost_averaging_inputs,
|
18 |
output as dollar_cost_averaging_output,
|
19 |
update_output as dollar_cost_averaging_update_output,
|
20 |
examples as dollar_cost_averaging_examples,
|
21 |
-
component_rows as dollar_cost_averaging_component_rows
|
|
|
22 |
)
|
23 |
from interface.retirement_planning_interface import (
|
24 |
input as retirement_planning_inputs,
|
25 |
output as retirement_planning_output,
|
26 |
update_output as retirement_update_output,
|
27 |
examples as retirement_planning_examples,
|
28 |
-
component_rows as retirement_planning_component_rows,
|
|
|
29 |
)
|
|
|
30 |
|
31 |
tabs_configuration = [
|
32 |
-
("🚀
|
33 |
-
("📈
|
34 |
-
("📉
|
35 |
-
("
|
36 |
]
|
37 |
|
38 |
def initial_load(*args):
|
@@ -48,7 +53,18 @@ def initial_load(*args):
|
|
48 |
return (rebalancing_results, share_price_trend_results, dollar_cost_averaging_results, retirement_results)
|
49 |
|
50 |
MARKDOWN = """
|
51 |
-
# TuneIt 🔥
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
"""
|
54 |
# Helper function to add buttons
|
@@ -87,8 +103,9 @@ def render_components(component_rows):
|
|
87 |
else:
|
88 |
row.render()
|
89 |
|
90 |
-
def create_tab(tab_name, inputs, outputs, update_fn, examples, component_rows):
|
91 |
-
with gr.
|
|
|
92 |
with gr.Row():
|
93 |
with gr.Column(elem_classes="input", scale=1):
|
94 |
render_components(component_rows)
|
@@ -100,11 +117,12 @@ def create_tab(tab_name, inputs, outputs, update_fn, examples, component_rows):
|
|
100 |
on_change(inputs, update_fn, outputs)
|
101 |
|
102 |
with gr.Blocks(css='style.css') as demo:
|
103 |
-
|
104 |
with gr.Column(elem_id="col-container"):
|
105 |
with gr.Tabs():
|
106 |
for tab in tabs_configuration:
|
107 |
create_tab(*tab)
|
|
|
108 |
|
109 |
# demo.load(
|
110 |
# initial_load,
|
|
|
4 |
output as rebalancing_output,
|
5 |
update_output as rebalancing_update_output,
|
6 |
examples as rebalancing_examples,
|
7 |
+
component_rows as rebalancing_component_rows,
|
8 |
+
header as rebalancing_title
|
9 |
)
|
10 |
from interface.share_price_trend_interface import (
|
11 |
input as share_price_trend_inputs,
|
12 |
output as share_price_trend_output,
|
13 |
update_output as share_price_trend_update_output,
|
14 |
examples as share_price_trend_examples,
|
15 |
+
component_rows as share_price_trend_component_rows,
|
16 |
+
header as share_price_trend_title
|
17 |
)
|
18 |
from interface.dollar_cost_averaging_interface import (
|
19 |
input as dollar_cost_averaging_inputs,
|
20 |
output as dollar_cost_averaging_output,
|
21 |
update_output as dollar_cost_averaging_update_output,
|
22 |
examples as dollar_cost_averaging_examples,
|
23 |
+
component_rows as dollar_cost_averaging_component_rows,
|
24 |
+
header as dollar_cost_averaging_title
|
25 |
)
|
26 |
from interface.retirement_planning_interface import (
|
27 |
input as retirement_planning_inputs,
|
28 |
output as retirement_planning_output,
|
29 |
update_output as retirement_update_output,
|
30 |
examples as retirement_planning_examples,
|
31 |
+
component_rows as retirement_planning_component_rows,
|
32 |
+
header as retirement_planning_title
|
33 |
)
|
34 |
+
from interface.about_interface import render_about_tab # "Support Us" 탭 추가
|
35 |
|
36 |
tabs_configuration = [
|
37 |
+
("🚀", rebalancing_inputs, rebalancing_output, rebalancing_update_output, rebalancing_examples, rebalancing_component_rows, rebalancing_title),
|
38 |
+
("📈", share_price_trend_inputs, share_price_trend_output, share_price_trend_update_output, share_price_trend_examples, share_price_trend_component_rows, share_price_trend_title),
|
39 |
+
("📉", dollar_cost_averaging_inputs, dollar_cost_averaging_output, dollar_cost_averaging_update_output, dollar_cost_averaging_examples, dollar_cost_averaging_component_rows, dollar_cost_averaging_title),
|
40 |
+
("💸", retirement_planning_inputs, retirement_planning_output, retirement_update_output, retirement_planning_examples, retirement_planning_component_rows, retirement_planning_title),
|
41 |
]
|
42 |
|
43 |
def initial_load(*args):
|
|
|
53 |
return (rebalancing_results, share_price_trend_results, dollar_cost_averaging_results, retirement_results)
|
54 |
|
55 |
MARKDOWN = """
|
56 |
+
# TuneIt 🔥 Investment Toolkit
|
57 |
+
|
58 |
+
Welcome to the **TuneIt Investment Toolkit**! This all-in-one platform is designed to help you optimize your financial strategies, whether you're balancing your portfolio, analyzing market trends, planning for retirement, or maximizing dividends.
|
59 |
+
|
60 |
+
Explore the tools below:
|
61 |
+
|
62 |
+
- `🚀 Re-Balancing Calculator`: Adjust your portfolio to maintain your desired asset allocation.
|
63 |
+
- `📈 Share Price Trend`: Analyze historical share price movements.
|
64 |
+
- `📉 Dollar Cost Averaging Calculator`: Assess the benefits of spreading out your investments.
|
65 |
+
- `💸 Dividend-Based Retirement Planning`: Calculate the investment required to achieve a dividend-based income stream during retirement.
|
66 |
+
|
67 |
+
Dive into each tool to enhance your investment decisions and secure your financial future.
|
68 |
|
69 |
"""
|
70 |
# Helper function to add buttons
|
|
|
103 |
else:
|
104 |
row.render()
|
105 |
|
106 |
+
def create_tab(tab_name, inputs, outputs, update_fn, examples, component_rows, header):
|
107 |
+
with gr.Tab(tab_name):
|
108 |
+
gr.Markdown(header)
|
109 |
with gr.Row():
|
110 |
with gr.Column(elem_classes="input", scale=1):
|
111 |
render_components(component_rows)
|
|
|
117 |
on_change(inputs, update_fn, outputs)
|
118 |
|
119 |
with gr.Blocks(css='style.css') as demo:
|
120 |
+
gr.Markdown(MARKDOWN, elem_id="col-container")
|
121 |
with gr.Column(elem_id="col-container"):
|
122 |
with gr.Tabs():
|
123 |
for tab in tabs_configuration:
|
124 |
create_tab(*tab)
|
125 |
+
render_about_tab() # "Support Us" 탭 추가
|
126 |
|
127 |
# demo.load(
|
128 |
# initial_load,
|
interface/about_interface.py
CHANGED
@@ -504,10 +504,11 @@ def render_about_tab():
|
|
504 |
|
505 |
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=M8SBRC396DPBW)
|
506 |
|
507 |
-
Or, if you prefer, you can also support us through
|
508 |
|
509 |
-
<a href="https://
|
510 |
-
<img src="https://
|
511 |
</a>
|
512 |
""")
|
513 |
|
|
|
|
504 |
|
505 |
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=M8SBRC396DPBW)
|
506 |
|
507 |
+
Or, if you prefer, you can also support us through KakaoPay at:
|
508 |
|
509 |
+
<a href="https://qr.kakaopay.com/Ej7jF6o7B" target="_blank">
|
510 |
+
<img src="https://t1.kakaocdn.net/pay_brand_admin/file/NvAxmhwMItNT4J2Uq1Rxt/ic-pfm.png" alt="Donate with KakaoPay" style="width: 150px;">
|
511 |
</a>
|
512 |
""")
|
513 |
|
514 |
+
|
interface/dollar_cost_averaging_interface.py
CHANGED
@@ -1,12 +1,15 @@
|
|
1 |
import gradio as gr
|
2 |
from modules.dollar_cost_averaging import dollar_cost_averaging
|
3 |
|
|
|
|
|
|
|
|
|
4 |
examples = [
|
5 |
["AAPL", 200, 9000, 560, 20000]
|
6 |
]
|
7 |
|
8 |
# Define the inputs
|
9 |
-
title = gr.Markdown("<h2 style='margin: 5px'>Dollar Cost Averaging Calculator</h2>")
|
10 |
stock_code = gr.Textbox(label="Stock Code", value="368590")
|
11 |
first_purchase = gr.Markdown("<h3 class='h3_title'>FIRST PURCHASE</h3>")
|
12 |
old_price = gr.Number(label="Old Price", value=18153)
|
|
|
1 |
import gradio as gr
|
2 |
from modules.dollar_cost_averaging import dollar_cost_averaging
|
3 |
|
4 |
+
header = """
|
5 |
+
# 📉 Dollar Cost Averaging Calculator
|
6 |
+
Use this calculator to evaluate the potential benefits of dollar-cost averaging as part of your investment strategy. Spread your investments over time to reduce risk.
|
7 |
+
"""
|
8 |
examples = [
|
9 |
["AAPL", 200, 9000, 560, 20000]
|
10 |
]
|
11 |
|
12 |
# Define the inputs
|
|
|
13 |
stock_code = gr.Textbox(label="Stock Code", value="368590")
|
14 |
first_purchase = gr.Markdown("<h3 class='h3_title'>FIRST PURCHASE</h3>")
|
15 |
old_price = gr.Number(label="Old Price", value=18153)
|
interface/rebalancing_interface.py
CHANGED
@@ -2,6 +2,10 @@ import gradio as gr
|
|
2 |
from modules.rebalancing import rebalancing_tool
|
3 |
from modules.utils import currency_codes, current_time
|
4 |
|
|
|
|
|
|
|
|
|
5 |
examples = [
|
6 |
["KRW", "458730 KRW 769 [4],\n368590 KRW 122 [1],", 0],
|
7 |
["KRW", "SCHD USD 9.044802 [8],\nQQQ USD 0.404082 [2],",0],
|
|
|
2 |
from modules.rebalancing import rebalancing_tool
|
3 |
from modules.utils import currency_codes, current_time
|
4 |
|
5 |
+
header = """
|
6 |
+
# 🚀 Re-Balancing Calculator
|
7 |
+
Re-balancing your portfolio can help you stay aligned with your investment goals. Use this calculator to determine the necessary adjustments to your current asset allocation.
|
8 |
+
"""
|
9 |
examples = [
|
10 |
["KRW", "458730 KRW 769 [4],\n368590 KRW 122 [1],", 0],
|
11 |
["KRW", "SCHD USD 9.044802 [8],\nQQQ USD 0.404082 [2],",0],
|
interface/retirement_planning_interface.py
CHANGED
@@ -1,13 +1,15 @@
|
|
1 |
import gradio as gr
|
2 |
from modules.retirement_planning import retirement_planning
|
3 |
|
|
|
|
|
|
|
4 |
# Define examples for retirement planning
|
5 |
examples = [
|
6 |
[38, 55, 85, 2000000, 3.0, 10000000, 1500000, 0, True, 8, 8, 3.3, 3.3]
|
7 |
]
|
8 |
|
9 |
# Define the input components
|
10 |
-
title = gr.Markdown("<h2 style='margin: 5px'>Dividend-Based Retirement Planning Calculator</h2>")
|
11 |
title_1 = gr.Markdown("<h3 class='h3_title'>Profile</h3>")
|
12 |
current_age = gr.Slider(label="Current Age (15-60 Years)", value=38, minimum=15, maximum=60, step=1)
|
13 |
retirement_age = gr.Slider(label="Retirement Age (Upto 70 Years)", value=55, minimum=15, maximum=70, step=1)
|
@@ -27,7 +29,7 @@ post_retirement_dividend_yield = gr.Number(label="Dividend Yield (Post-retiremen
|
|
27 |
|
28 |
input = [current_age, retirement_age, life_expectancy, monthly_income_required, inflation_rate, initial_investment, monthly_contribution, annual_increase_in_monthly_contribution, reinvest_dividends, pre_retirement_dividend_growth, post_retirement_dividend_growth, pre_retirement_dividend_yield, post_retirement_dividend_yield]
|
29 |
output = gr.HTML()
|
30 |
-
component_rows = [
|
31 |
title_1, [current_age, retirement_age, life_expectancy],[monthly_income_required, inflation_rate],
|
32 |
title_2, [initial_investment, monthly_contribution, annual_increase_in_monthly_contribution], [reinvest_dividends],
|
33 |
title_3, [pre_retirement_dividend_growth, post_retirement_dividend_growth], [pre_retirement_dividend_yield, post_retirement_dividend_yield]
|
|
|
1 |
import gradio as gr
|
2 |
from modules.retirement_planning import retirement_planning
|
3 |
|
4 |
+
header = """# 💸 Dividend-Based Retirement Planning Calculator
|
5 |
+
Plan your retirement around dividend income. This calculator helps you estimate how much you need to invest to generate a desired amount of annual income through dividends, ensuring a stable and predictable income stream during your retirement years.
|
6 |
+
"""
|
7 |
# Define examples for retirement planning
|
8 |
examples = [
|
9 |
[38, 55, 85, 2000000, 3.0, 10000000, 1500000, 0, True, 8, 8, 3.3, 3.3]
|
10 |
]
|
11 |
|
12 |
# Define the input components
|
|
|
13 |
title_1 = gr.Markdown("<h3 class='h3_title'>Profile</h3>")
|
14 |
current_age = gr.Slider(label="Current Age (15-60 Years)", value=38, minimum=15, maximum=60, step=1)
|
15 |
retirement_age = gr.Slider(label="Retirement Age (Upto 70 Years)", value=55, minimum=15, maximum=70, step=1)
|
|
|
29 |
|
30 |
input = [current_age, retirement_age, life_expectancy, monthly_income_required, inflation_rate, initial_investment, monthly_contribution, annual_increase_in_monthly_contribution, reinvest_dividends, pre_retirement_dividend_growth, post_retirement_dividend_growth, pre_retirement_dividend_yield, post_retirement_dividend_yield]
|
31 |
output = gr.HTML()
|
32 |
+
component_rows = [
|
33 |
title_1, [current_age, retirement_age, life_expectancy],[monthly_income_required, inflation_rate],
|
34 |
title_2, [initial_investment, monthly_contribution, annual_increase_in_monthly_contribution], [reinvest_dividends],
|
35 |
title_3, [pre_retirement_dividend_growth, post_retirement_dividend_growth], [pre_retirement_dividend_yield, post_retirement_dividend_yield]
|
interface/share_price_trend_interface.py
CHANGED
@@ -1,13 +1,16 @@
|
|
1 |
import gradio as gr
|
2 |
from modules.share_price_trend import share_price_trend, gradio_interface
|
3 |
|
|
|
|
|
|
|
|
|
4 |
examples = [
|
5 |
["AAPL,GOOGL,MSFT", 90],
|
6 |
["SCHD,QQQ", 365]
|
7 |
]
|
8 |
|
9 |
# Define Gradio components for inputs
|
10 |
-
title = gr.Markdown("<h2 style='margin: 5px'>Share Price Trend</h2>")
|
11 |
stock_codes = gr.Textbox(
|
12 |
label="Stock Codes",
|
13 |
# info="Enter stock codes separated by comma.",
|
@@ -18,8 +21,7 @@ period = gr.Slider(
|
|
18 |
label="Number of Days",
|
19 |
value=365,
|
20 |
minimum=7,
|
21 |
-
step = 1
|
22 |
-
randomize = True
|
23 |
)
|
24 |
|
25 |
# Define output component
|
|
|
1 |
import gradio as gr
|
2 |
from modules.share_price_trend import share_price_trend, gradio_interface
|
3 |
|
4 |
+
header = """
|
5 |
+
# 📈 Share Price Trend
|
6 |
+
Track the trends in share prices over time. This tool helps you analyze historical price movements to inform your investment decisions.
|
7 |
+
"""
|
8 |
examples = [
|
9 |
["AAPL,GOOGL,MSFT", 90],
|
10 |
["SCHD,QQQ", 365]
|
11 |
]
|
12 |
|
13 |
# Define Gradio components for inputs
|
|
|
14 |
stock_codes = gr.Textbox(
|
15 |
label="Stock Codes",
|
16 |
# info="Enter stock codes separated by comma.",
|
|
|
21 |
label="Number of Days",
|
22 |
value=365,
|
23 |
minimum=7,
|
24 |
+
step = 1
|
|
|
25 |
)
|
26 |
|
27 |
# Define output component
|
modules/rebalancing.py
CHANGED
@@ -248,7 +248,7 @@ def generate_rebalancing_analysis(portfolio, target_ratios, total_value, main_cu
|
|
248 |
<tbody>
|
249 |
{''.join(
|
250 |
f"<tr>"
|
251 |
-
f"<td
|
252 |
f"<td>{format_value(adj['current_value'])}</td>"
|
253 |
f"<td>{adj['current_value_pct'] * 100:.1f}%</td>"
|
254 |
f"<td style='text-align: center !important;'><span class='highlight-edit'>{adj['target_weight'] * 100:.0f}%</span></td>"
|
|
|
248 |
<tbody>
|
249 |
{''.join(
|
250 |
f"<tr>"
|
251 |
+
f"<td>{adj['stock_code'].upper()}</td>"
|
252 |
f"<td>{format_value(adj['current_value'])}</td>"
|
253 |
f"<td>{adj['current_value_pct'] * 100:.1f}%</td>"
|
254 |
f"<td style='text-align: center !important;'><span class='highlight-edit'>{adj['target_weight'] * 100:.0f}%</span></td>"
|
modules/utils.py
CHANGED
@@ -73,7 +73,7 @@ def get_color_for_label(index, color_map, num_labels):
|
|
73 |
color_map_storage[index] = cmap(1 - index / (num_labels - 1))
|
74 |
return color_map_storage[index]
|
75 |
|
76 |
-
def plot_donut_chart(data, color_map='Blues', font_path='Quicksand-Regular.ttf', legend_fontsize=30):
|
77 |
# 데이터 필터링: 비중이 0이 아닌 항목만 추출
|
78 |
filtered_data = {k: v for k, v in data.items() if v > 0}
|
79 |
|
|
|
73 |
color_map_storage[index] = cmap(1 - index / (num_labels - 1))
|
74 |
return color_map_storage[index]
|
75 |
|
76 |
+
def plot_donut_chart(data, color_map='Blues', font_path='./font/Quicksand-Regular.ttf', legend_fontsize=30):
|
77 |
# 데이터 필터링: 비중이 0이 아닌 항목만 추출
|
78 |
filtered_data = {k: v for k, v in data.items() if v > 0}
|
79 |
|
style.css
CHANGED
@@ -19,6 +19,17 @@
|
|
19 |
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;700&display=swap');
|
20 |
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
|
21 |
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
:root {
|
24 |
--background-color-light: #ffffff;
|
@@ -165,6 +176,10 @@
|
|
165 |
border-collapse: collapse;
|
166 |
}
|
167 |
|
|
|
|
|
|
|
|
|
168 |
.table-container th, .table-container td {
|
169 |
border: 1px solid #ddd;
|
170 |
padding: 8px;
|
@@ -183,6 +198,7 @@
|
|
183 |
position: sticky;
|
184 |
left: 0;
|
185 |
z-index: 1;
|
|
|
186 |
}
|
187 |
|
188 |
.table-container th:first-child {
|
|
|
19 |
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;700&display=swap');
|
20 |
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
|
21 |
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap');
|
22 |
+
/* @font-face {
|
23 |
+
font-family: 'Paperlogy Light';
|
24 |
+
src: url('/file=font/Paperlogy/Paperlogy-3Light.ttf') format('truetype');
|
25 |
+
font-weight: normal;
|
26 |
+
font-style: normal;
|
27 |
+
}
|
28 |
+
|
29 |
+
body {
|
30 |
+
font-family: 'Paperlogy Light', sans-serif;
|
31 |
+
} */
|
32 |
+
|
33 |
|
34 |
:root {
|
35 |
--background-color-light: #ffffff;
|
|
|
176 |
border-collapse: collapse;
|
177 |
}
|
178 |
|
179 |
+
.table-container td {
|
180 |
+
text-align: end;
|
181 |
+
}
|
182 |
+
|
183 |
.table-container th, .table-container td {
|
184 |
border: 1px solid #ddd;
|
185 |
padding: 8px;
|
|
|
198 |
position: sticky;
|
199 |
left: 0;
|
200 |
z-index: 1;
|
201 |
+
text-align: left;
|
202 |
}
|
203 |
|
204 |
.table-container th:first-child {
|