Spaces:
Running
Running
Upload 18 files
Browse files- interface/dollar_cost_averaging_interface copy.py +22 -0
- interface/dollar_cost_averaging_interface.py +6 -5
- interface/retirement_planning_interface.py +2 -2
- interface/share_price_trend_interface.py +4 -4
- modules/dollar_cost_averaging copy.py +103 -0
- modules/dollar_cost_averaging.py +32 -24
- modules/rebalancing.py +1 -1
- modules/share_price_trend.py +28 -89
interface/dollar_cost_averaging_interface copy.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from modules.dollar_cost_averaging import dollar_cost_averaging
|
3 |
+
|
4 |
+
examples = [
|
5 |
+
[1000, 9000, 560, 20000]
|
6 |
+
]
|
7 |
+
# Define the inputs
|
8 |
+
title = gr.Markdown("<h2 style='margin: 5px'>Dollar Cost Averaging Calculator</h2>")
|
9 |
+
first_purchase = gr.Markdown("<h3 class='h3_title'>FIRST PURCHASE</h3>")
|
10 |
+
old_price = gr.Number(label="Old Price", value=18150)
|
11 |
+
old_quantity = gr.Number(label="Quantity", value=95)
|
12 |
+
second_purchase = gr.Markdown("<h3 class='h3_title'>SECOND PURCHASE</h3>")
|
13 |
+
new_price = gr.Number(label="New Price", value=17705)
|
14 |
+
new_quantity = gr.Number(label="Quantity", value=0)
|
15 |
+
|
16 |
+
input = [old_price, old_quantity, new_price, new_quantity]
|
17 |
+
output = gr.HTML()
|
18 |
+
component_rows= [first_purchase, old_price, old_quantity, second_purchase, new_price, new_quantity]
|
19 |
+
|
20 |
+
# Define the update function
|
21 |
+
def update_output(*args):
|
22 |
+
return dollar_cost_averaging(*args)
|
interface/dollar_cost_averaging_interface.py
CHANGED
@@ -2,20 +2,21 @@ import gradio as gr
|
|
2 |
from modules.dollar_cost_averaging import dollar_cost_averaging
|
3 |
|
4 |
examples = [
|
5 |
-
[
|
6 |
]
|
|
|
7 |
# Define the inputs
|
8 |
title = gr.Markdown("<h2 style='margin: 5px'>Dollar Cost Averaging Calculator</h2>")
|
|
|
9 |
first_purchase = gr.Markdown("<h3 class='h3_title'>FIRST PURCHASE</h3>")
|
10 |
old_price = gr.Number(label="Old Price", value=18150)
|
11 |
old_quantity = gr.Number(label="Quantity", value=95)
|
12 |
second_purchase = gr.Markdown("<h3 class='h3_title'>SECOND PURCHASE</h3>")
|
13 |
-
|
14 |
-
new_quantity = gr.Number(label="Quantity", value=0)
|
15 |
|
16 |
-
input = [old_price, old_quantity,
|
17 |
output = gr.HTML()
|
18 |
-
component_rows= [first_purchase, old_price, old_quantity, second_purchase,
|
19 |
|
20 |
# Define the update function
|
21 |
def update_output(*args):
|
|
|
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=18150)
|
13 |
old_quantity = gr.Number(label="Quantity", value=95)
|
14 |
second_purchase = gr.Markdown("<h3 class='h3_title'>SECOND PURCHASE</h3>")
|
15 |
+
new_quantity = gr.Slider(label="Quantity", value=0)
|
|
|
16 |
|
17 |
+
input = [stock_code, old_price, old_quantity, new_quantity]
|
18 |
output = gr.HTML()
|
19 |
+
component_rows = [stock_code, first_purchase, old_price, old_quantity, second_purchase, new_quantity]
|
20 |
|
21 |
# Define the update function
|
22 |
def update_output(*args):
|
interface/retirement_planning_interface.py
CHANGED
@@ -9,14 +9,14 @@ examples = [
|
|
9 |
# Define the input components
|
10 |
title = gr.Markdown("<h2 style='margin: 5px'>Retirement Planning</h2>")
|
11 |
title_profile = gr.Markdown("<h3 class='h3_title'>PROFILE</h3>")
|
12 |
-
current_age = gr.Slider(label="Current Age (15-60 Years)", value=
|
13 |
retirement_age = gr.Slider(label="Retirement Age (Upto 70 Years)", value=55, minimum=15, maximum=70, step=1)
|
14 |
life_expectancy = gr.Slider(label="Life Expectancy (Upto 100 Years)", value=80, minimum=30, maximum=100, step=1)
|
15 |
title_savings = gr.Markdown("<h3 class='h3_title'>SAVINGS</h3>")
|
16 |
monthly_income_required = gr.Number(label="Monthly Income Required (CPP)", value=2000000)
|
17 |
inflation_rate = gr.Number(label="Inflation Rate (%)", value=3)
|
18 |
current_investment = gr.Number(label="Current Investment", value=10000000)
|
19 |
-
monthly_investment = gr.Number(label="Monthly Investment", value=
|
20 |
annual_increase_in_monthly_investment = gr.Number(label="Annual Increase in Monthly Investment", value=0) # 추가된 입력
|
21 |
reinvest_dividends = gr.Checkbox(label="Reinvest Dividends", value=True)
|
22 |
title_growth = gr.Markdown("<h3 class='h3_title'>GROWTH</h3>")
|
|
|
9 |
# Define the input components
|
10 |
title = gr.Markdown("<h2 style='margin: 5px'>Retirement Planning</h2>")
|
11 |
title_profile = 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)
|
14 |
life_expectancy = gr.Slider(label="Life Expectancy (Upto 100 Years)", value=80, minimum=30, maximum=100, step=1)
|
15 |
title_savings = gr.Markdown("<h3 class='h3_title'>SAVINGS</h3>")
|
16 |
monthly_income_required = gr.Number(label="Monthly Income Required (CPP)", value=2000000)
|
17 |
inflation_rate = gr.Number(label="Inflation Rate (%)", value=3)
|
18 |
current_investment = gr.Number(label="Current Investment", value=10000000)
|
19 |
+
monthly_investment = gr.Number(label="Monthly Investment", value=1000000)
|
20 |
annual_increase_in_monthly_investment = gr.Number(label="Annual Increase in Monthly Investment", value=0) # 추가된 입력
|
21 |
reinvest_dividends = gr.Checkbox(label="Reinvest Dividends", value=True)
|
22 |
title_growth = gr.Markdown("<h3 class='h3_title'>GROWTH</h3>")
|
interface/share_price_trend_interface.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import gradio as gr
|
2 |
-
from modules.share_price_trend import share_price_trend
|
3 |
|
4 |
examples = [
|
5 |
["AAPL,GOOGL,MSFT", 90],
|
@@ -17,14 +17,14 @@ stock_codes = gr.Textbox(
|
|
17 |
period = gr.Slider(
|
18 |
label="Number of Days",
|
19 |
value=90,
|
20 |
-
|
21 |
)
|
22 |
|
23 |
# Define output component
|
24 |
input = [stock_codes, period]
|
25 |
-
output = gr.
|
26 |
component_rows = [[stock_codes], [period]]
|
27 |
|
28 |
# Define the update function
|
29 |
def update_output(*args):
|
30 |
-
return
|
|
|
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],
|
|
|
17 |
period = gr.Slider(
|
18 |
label="Number of Days",
|
19 |
value=90,
|
20 |
+
minimum=7
|
21 |
)
|
22 |
|
23 |
# Define output component
|
24 |
input = [stock_codes, period]
|
25 |
+
output = gr.Plot()
|
26 |
component_rows = [[stock_codes], [period]]
|
27 |
|
28 |
# Define the update function
|
29 |
def update_output(*args):
|
30 |
+
return gradio_interface(*args)
|
modules/dollar_cost_averaging copy.py
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules.utils import load_css
|
2 |
+
|
3 |
+
def calculate_dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
4 |
+
# 입력값을 숫자로 변환 (각 입력값이 None일 경우 0.0으로 설정)
|
5 |
+
old_avg_price = float(old_avg_price) if old_avg_price else 0.0
|
6 |
+
old_quantity = float(old_quantity) if old_quantity else 0.0
|
7 |
+
new_price = float(new_price) if new_price else 0.0
|
8 |
+
new_quantity = float(new_quantity) if new_quantity else 0.0
|
9 |
+
|
10 |
+
# 현재 투자 금액 계산 (이전 평균 가격 * 이전 수량)
|
11 |
+
current_investment = old_avg_price * old_quantity
|
12 |
+
# 추가 투자 금액 계산 (새 가격 * 새 수량)
|
13 |
+
additional_investment = new_price * new_quantity
|
14 |
+
# 총 투자 금액 계산 (현재 투자 금액 + 추가 투자 금액)
|
15 |
+
total_investment = current_investment + additional_investment
|
16 |
+
# 총 주식 수 계산 (이전 수량 + 새 수량)
|
17 |
+
total_quantity = old_quantity + new_quantity
|
18 |
+
# 새 평균 가격 계산 (총 투자 금액 / 총 주식 수)
|
19 |
+
new_avg_price = total_investment / total_quantity if total_quantity != 0 else 0.0
|
20 |
+
# 이전 수익률 계산 (이전 평균 가격을 기준으로)
|
21 |
+
old_return = (new_price / old_avg_price - 1) * 100 if old_avg_price != 0 else 0.0
|
22 |
+
# 새로운 수익률 계산 (새 가격 / 새 평균 가격 - 1) * 100
|
23 |
+
new_return = (new_price / new_avg_price - 1) * 100 if new_avg_price != 0 else 0.0
|
24 |
+
|
25 |
+
# 새 평균 가격, 총 수량, 총 투자 금액, 새로운 수익률, 추가 투자 금액, 이전 수익률 반환
|
26 |
+
return new_avg_price, total_quantity, total_investment, new_return, additional_investment, old_return
|
27 |
+
|
28 |
+
def dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
29 |
+
css = load_css()
|
30 |
+
|
31 |
+
# 입력값을 숫자로 변환
|
32 |
+
old_avg_price = float(old_avg_price) if old_avg_price else 0.0
|
33 |
+
old_quantity = float(old_quantity) if old_quantity else 0.0
|
34 |
+
new_price = float(new_price) if new_price else 0.0
|
35 |
+
new_quantity = float(new_quantity) if new_quantity else 0.0
|
36 |
+
|
37 |
+
# 평균 가격, 총 수량, 총 투자 금액, 수익률 및 추가 투자 금액 계산
|
38 |
+
new_avg_price, total_quantity, total_investment, new_return, additional_investment, old_return = calculate_dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity)
|
39 |
+
|
40 |
+
# 수익률에 따른 클래스 설정
|
41 |
+
emoji_return = ""
|
42 |
+
new_return_class = ""
|
43 |
+
old_return_class = ""
|
44 |
+
if new_return > old_return:
|
45 |
+
emoji_return = "💧"
|
46 |
+
elif new_return < old_return:
|
47 |
+
emoji_return = "🔥"
|
48 |
+
else:
|
49 |
+
emoji_return = ""
|
50 |
+
|
51 |
+
if new_return > 0:
|
52 |
+
new_return_class = f"<span style='color: #4caf50;'>{new_return:+,.2f}%</span>"
|
53 |
+
elif new_return < 0:
|
54 |
+
new_return_class = f"<span style='color: #f44336;'>{new_return:,.2f}%</span>"
|
55 |
+
else:
|
56 |
+
new_return_class = f"<span><strong>0</strong></span>"
|
57 |
+
|
58 |
+
if old_return > 0:
|
59 |
+
old_return_class = f"<span style='color: #4caf50;'>{old_return:+,.2f}%</span>"
|
60 |
+
elif old_return < 0:
|
61 |
+
old_return_class = f"<span style='color: #f44336;'>{old_return:,.2f}%</span>"
|
62 |
+
else:
|
63 |
+
old_return_class = f"<span><strong>0</strong></span>"
|
64 |
+
|
65 |
+
# HTML 결과 생성
|
66 |
+
result_html = css + f"""
|
67 |
+
<div class="wrap-text">
|
68 |
+
<div>
|
69 |
+
<div style="margin-bottom: 1.5rem;">
|
70 |
+
<!-- 이전 수익률 표시 -->
|
71 |
+
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Old Price</div>
|
72 |
+
<div style="font-size: 1.5rem; color: #1c75bc;">
|
73 |
+
<span style='color: #1678fb; font-weight: bold;'>{old_avg_price:,.0f}</span>
|
74 |
+
<span style='font-size: 1rem;'>{old_return_class}</span>
|
75 |
+
</div>
|
76 |
+
<hr style="margin: 1.5rem 0;">
|
77 |
+
</div>
|
78 |
+
</div>
|
79 |
+
<div>
|
80 |
+
<div style="margin-bottom: 1.5rem;">
|
81 |
+
<!-- 새로운 수익률 표시 -->
|
82 |
+
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Average Price</div>
|
83 |
+
<div style="font-size: 1.5rem; color: #1c75bc;">
|
84 |
+
<span style='color: #1678fb; font-weight: bold;'>{new_avg_price:,.0f}</span>
|
85 |
+
<span style='font-size: 1rem;'>{new_return_class}</span>
|
86 |
+
</div>
|
87 |
+
<hr style="margin: 1.5rem 0;">
|
88 |
+
</div>
|
89 |
+
</div>
|
90 |
+
<div>
|
91 |
+
<div style="margin-bottom: 1.5rem;">
|
92 |
+
<!-- 추가 투자 금액 표시 -->
|
93 |
+
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Additional Investment</div>
|
94 |
+
<div style="font-size: 1.5rem; font-weight: bold; color: #1c75bc;">
|
95 |
+
<span style='color: #1678fb'>{additional_investment:,.0f}</span>
|
96 |
+
</div>
|
97 |
+
<hr style="margin: 1.5rem 0;">
|
98 |
+
</div>
|
99 |
+
</div>
|
100 |
+
|
101 |
+
</div>
|
102 |
+
"""
|
103 |
+
return result_html
|
modules/dollar_cost_averaging.py
CHANGED
@@ -1,43 +1,47 @@
|
|
|
|
|
|
1 |
from modules.utils import load_css
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
def calculate_dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
4 |
-
# 입력값을 숫자로 변환 (각 입력값이 None일 경우 0.0으로 설정)
|
5 |
old_avg_price = float(old_avg_price) if old_avg_price else 0.0
|
6 |
old_quantity = float(old_quantity) if old_quantity else 0.0
|
7 |
new_price = float(new_price) if new_price else 0.0
|
8 |
new_quantity = float(new_quantity) if new_quantity else 0.0
|
9 |
|
10 |
-
|
|
|
|
|
11 |
current_investment = old_avg_price * old_quantity
|
12 |
-
# 추가 투자 금액 계산 (새 가격 * 새 수량)
|
13 |
additional_investment = new_price * new_quantity
|
14 |
-
# 총 투자 금액 계산 (현재 투자 금액 + 추가 투자 금액)
|
15 |
total_investment = current_investment + additional_investment
|
16 |
-
# 총 주식 수 계산 (이전 수량 + 새 수량)
|
17 |
total_quantity = old_quantity + new_quantity
|
18 |
-
# 새 평균 가격 계산 (총 투자 금액 / 총 주식 수)
|
19 |
new_avg_price = total_investment / total_quantity if total_quantity != 0 else 0.0
|
20 |
-
# 이전 수익률 계산 (이전 평균 가격을 기준으로)
|
21 |
old_return = (new_price / old_avg_price - 1) * 100 if old_avg_price != 0 else 0.0
|
22 |
-
# 새로운 수익률 계산 (새 가격 / 새 평균 가격 - 1) * 100
|
23 |
new_return = (new_price / new_avg_price - 1) * 100 if new_avg_price != 0 else 0.0
|
24 |
-
|
25 |
-
# 새 평균 가격, 총 수량, 총 투자 금액, 새로운 수익률, 추가 투자 금액, 이전 수익률 반환
|
26 |
return new_avg_price, total_quantity, total_investment, new_return, additional_investment, old_return
|
27 |
|
28 |
-
def dollar_cost_averaging(old_avg_price, old_quantity,
|
29 |
css = load_css()
|
30 |
-
|
31 |
-
#
|
|
|
|
|
|
|
32 |
old_avg_price = float(old_avg_price) if old_avg_price else 0.0
|
33 |
old_quantity = float(old_quantity) if old_quantity else 0.0
|
34 |
-
new_price = float(new_price) if new_price else 0.0
|
35 |
new_quantity = float(new_quantity) if new_quantity else 0.0
|
36 |
|
37 |
-
# 평균 가격, 총 수량, 총 투자 금액, 수익률 및 추가 투자 금액 계산
|
38 |
new_avg_price, total_quantity, total_investment, new_return, additional_investment, old_return = calculate_dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity)
|
39 |
|
40 |
-
# 수익률에 따른 클래스 설정
|
41 |
emoji_return = ""
|
42 |
new_return_class = ""
|
43 |
old_return_class = ""
|
@@ -45,7 +49,7 @@ def dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
|
45 |
emoji_return = "💧"
|
46 |
elif new_return < old_return:
|
47 |
emoji_return = "🔥"
|
48 |
-
else:
|
49 |
emoji_return = ""
|
50 |
|
51 |
if new_return > 0:
|
@@ -62,12 +66,19 @@ def dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
|
62 |
else:
|
63 |
old_return_class = f"<span><strong>0</strong></span>"
|
64 |
|
65 |
-
# HTML 결과 생성
|
66 |
result_html = css + f"""
|
67 |
<div class="wrap-text">
|
68 |
<div>
|
69 |
<div style="margin-bottom: 1.5rem;">
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Old Price</div>
|
72 |
<div style="font-size: 1.5rem; color: #1c75bc;">
|
73 |
<span style='color: #1678fb; font-weight: bold;'>{old_avg_price:,.0f}</span>
|
@@ -75,10 +86,9 @@ def dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
|
75 |
</div>
|
76 |
<hr style="margin: 1.5rem 0;">
|
77 |
</div>
|
78 |
-
</div>
|
79 |
-
|
80 |
<div style="margin-bottom: 1.5rem;">
|
81 |
-
<!-- 새로운 수익률 표시 -->
|
82 |
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Average Price</div>
|
83 |
<div style="font-size: 1.5rem; color: #1c75bc;">
|
84 |
<span style='color: #1678fb; font-weight: bold;'>{new_avg_price:,.0f}</span>
|
@@ -89,7 +99,6 @@ def dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
|
89 |
</div>
|
90 |
<div>
|
91 |
<div style="margin-bottom: 1.5rem;">
|
92 |
-
<!-- 추가 투자 금액 표시 -->
|
93 |
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Additional Investment</div>
|
94 |
<div style="font-size: 1.5rem; font-weight: bold; color: #1c75bc;">
|
95 |
<span style='color: #1678fb'>{additional_investment:,.0f}</span>
|
@@ -97,7 +106,6 @@ def dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
|
97 |
<hr style="margin: 1.5rem 0;">
|
98 |
</div>
|
99 |
</div>
|
100 |
-
|
101 |
</div>
|
102 |
"""
|
103 |
return result_html
|
|
|
1 |
+
import yfinance as yf
|
2 |
+
import FinanceDataReader as fdr
|
3 |
from modules.utils import load_css
|
4 |
|
5 |
+
def get_stock_price(stock_code):
|
6 |
+
try:
|
7 |
+
df = fdr.DataReader(stock_code)
|
8 |
+
return df['Close'].iloc[-1]
|
9 |
+
except Exception as e:
|
10 |
+
# 에러 발생 시 0.0으로 설정하고, 오류 메시지를 반환
|
11 |
+
return None
|
12 |
+
|
13 |
def calculate_dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity):
|
|
|
14 |
old_avg_price = float(old_avg_price) if old_avg_price else 0.0
|
15 |
old_quantity = float(old_quantity) if old_quantity else 0.0
|
16 |
new_price = float(new_price) if new_price else 0.0
|
17 |
new_quantity = float(new_quantity) if new_quantity else 0.0
|
18 |
|
19 |
+
if old_quantity == 0 and new_quantity == 0:
|
20 |
+
return 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
|
21 |
+
|
22 |
current_investment = old_avg_price * old_quantity
|
|
|
23 |
additional_investment = new_price * new_quantity
|
|
|
24 |
total_investment = current_investment + additional_investment
|
|
|
25 |
total_quantity = old_quantity + new_quantity
|
|
|
26 |
new_avg_price = total_investment / total_quantity if total_quantity != 0 else 0.0
|
|
|
27 |
old_return = (new_price / old_avg_price - 1) * 100 if old_avg_price != 0 else 0.0
|
|
|
28 |
new_return = (new_price / new_avg_price - 1) * 100 if new_avg_price != 0 else 0.0
|
29 |
+
|
|
|
30 |
return new_avg_price, total_quantity, total_investment, new_return, additional_investment, old_return
|
31 |
|
32 |
+
def dollar_cost_averaging(stock_code, old_avg_price, old_quantity, new_quantity):
|
33 |
css = load_css()
|
34 |
+
|
35 |
+
# 주식 가격 가져오기
|
36 |
+
new_price = get_stock_price(stock_code)
|
37 |
+
|
38 |
+
new_price = float(new_price) if new_price else 0.0
|
39 |
old_avg_price = float(old_avg_price) if old_avg_price else 0.0
|
40 |
old_quantity = float(old_quantity) if old_quantity else 0.0
|
|
|
41 |
new_quantity = float(new_quantity) if new_quantity else 0.0
|
42 |
|
|
|
43 |
new_avg_price, total_quantity, total_investment, new_return, additional_investment, old_return = calculate_dollar_cost_averaging(old_avg_price, old_quantity, new_price, new_quantity)
|
44 |
|
|
|
45 |
emoji_return = ""
|
46 |
new_return_class = ""
|
47 |
old_return_class = ""
|
|
|
49 |
emoji_return = "💧"
|
50 |
elif new_return < old_return:
|
51 |
emoji_return = "🔥"
|
52 |
+
else:
|
53 |
emoji_return = ""
|
54 |
|
55 |
if new_return > 0:
|
|
|
66 |
else:
|
67 |
old_return_class = f"<span><strong>0</strong></span>"
|
68 |
|
|
|
69 |
result_html = css + f"""
|
70 |
<div class="wrap-text">
|
71 |
<div>
|
72 |
<div style="margin-bottom: 1.5rem;">
|
73 |
+
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">New Price</div>
|
74 |
+
<div style="font-size: 1.5rem; color: #1c75bc;">
|
75 |
+
<span style='color: #1678fb; font-weight: bold;'>{new_price:,}</span>
|
76 |
+
</div>
|
77 |
+
<hr style="margin: 1.5rem 0;">
|
78 |
+
</div>
|
79 |
+
</div>
|
80 |
+
<div>
|
81 |
+
<div style="margin-bottom: 1.5rem;">
|
82 |
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Old Price</div>
|
83 |
<div style="font-size: 1.5rem; color: #1c75bc;">
|
84 |
<span style='color: #1678fb; font-weight: bold;'>{old_avg_price:,.0f}</span>
|
|
|
86 |
</div>
|
87 |
<hr style="margin: 1.5rem 0;">
|
88 |
</div>
|
89 |
+
</div>
|
90 |
+
<div>
|
91 |
<div style="margin-bottom: 1.5rem;">
|
|
|
92 |
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Average Price</div>
|
93 |
<div style="font-size: 1.5rem; color: #1c75bc;">
|
94 |
<span style='color: #1678fb; font-weight: bold;'>{new_avg_price:,.0f}</span>
|
|
|
99 |
</div>
|
100 |
<div>
|
101 |
<div style="margin-bottom: 1.5rem;">
|
|
|
102 |
<div style="font-size: 1.5rem; margin-top: 1.5rem; margin-bottom: 1.5rem;">Additional Investment</div>
|
103 |
<div style="font-size: 1.5rem; font-weight: bold; color: #1c75bc;">
|
104 |
<span style='color: #1678fb'>{additional_investment:,.0f}</span>
|
|
|
106 |
<hr style="margin: 1.5rem 0;">
|
107 |
</div>
|
108 |
</div>
|
|
|
109 |
</div>
|
110 |
"""
|
111 |
return result_html
|
modules/rebalancing.py
CHANGED
@@ -261,6 +261,6 @@ def rebalancing_tool(main_currency, holdings, cash_amount, allow_selling):
|
|
261 |
portfolio_info = generate_portfolio_info(portfolio, total_value, main_currency)
|
262 |
rebalancing_analysis = generate_rebalancing_analysis(portfolio, target_ratios, total_value, main_currency, cash_amount, allow_selling)
|
263 |
|
264 |
-
return
|
265 |
except Exception as e:
|
266 |
return f"<p style='color: red;'>An error occurred: {e}</p>"
|
|
|
261 |
portfolio_info = generate_portfolio_info(portfolio, total_value, main_currency)
|
262 |
rebalancing_analysis = generate_rebalancing_analysis(portfolio, target_ratios, total_value, main_currency, cash_amount, allow_selling)
|
263 |
|
264 |
+
return rebalancing_analysis
|
265 |
except Exception as e:
|
266 |
return f"<p style='color: red;'>An error occurred: {e}</p>"
|
modules/share_price_trend.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
import io
|
2 |
-
import matplotlib.pyplot as plt
|
3 |
-
import FinanceDataReader as fdr
|
4 |
import pandas as pd
|
|
|
|
|
|
|
5 |
from concurrent.futures import ThreadPoolExecutor, as_completed
|
6 |
|
7 |
def get_stock_prices(stock_code, days):
|
@@ -32,97 +33,35 @@ def share_price_trend(stock_codes, days):
|
|
32 |
print(f"<p style='color: red;'>Failed to fetch data for {stock_code}: {e}</p>")
|
33 |
|
34 |
if not stock_prices:
|
35 |
-
return "
|
36 |
|
37 |
-
|
38 |
-
plt.style.use('tableau-colorblind10')
|
39 |
|
40 |
-
fig, ax = plt.subplots(figsize=(8, 4.5))
|
41 |
for stock_code, prices in stock_prices.items():
|
42 |
relative_prices = prices / prices.iloc[0]
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
|
|
|
|
|
|
53 |
|
54 |
-
|
55 |
-
ax.grid(True, which='both', linestyle='--', linewidth=0.5)
|
56 |
-
|
57 |
-
ax.legend()
|
58 |
-
plt.tight_layout()
|
59 |
-
|
60 |
-
svg_graph = io.StringIO()
|
61 |
-
plt.savefig(svg_graph, format='svg')
|
62 |
-
svg_graph.seek(0)
|
63 |
-
svg_data = svg_graph.getvalue()
|
64 |
-
plt.close()
|
65 |
-
|
66 |
-
svg_data = svg_data.replace('<svg ', '<svg width="100%" height="100%" ')
|
67 |
-
svg_data = svg_data.replace('</svg>', '''
|
68 |
-
<defs>
|
69 |
-
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
|
70 |
-
<stop offset="0%" style="stop-color:rgb(173,216,230);stop-opacity:1" />
|
71 |
-
<stop offset="100%" style="stop-color:rgb(0,191,255);stop-opacity:1" />
|
72 |
-
</linearGradient>
|
73 |
-
<filter id="dropshadow" height="130%">
|
74 |
-
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
|
75 |
-
<feOffset dx="2" dy="2" result="offsetblur"/>
|
76 |
-
<feMerge>
|
77 |
-
<feMergeNode/>
|
78 |
-
<feMergeNode in="SourceGraphic"/>
|
79 |
-
</feMerge>
|
80 |
-
</filter>
|
81 |
-
</defs>
|
82 |
-
<style>
|
83 |
-
@keyframes lineAnimation {
|
84 |
-
from {
|
85 |
-
stroke-dasharray: 0, 1000;
|
86 |
-
}
|
87 |
-
to {
|
88 |
-
stroke-dasharray: 1000, 0;
|
89 |
-
}
|
90 |
-
}
|
91 |
-
path {
|
92 |
-
animation: lineAnimation 1s linear forwards;
|
93 |
-
}
|
94 |
-
</style>
|
95 |
-
</svg>''')
|
96 |
-
|
97 |
-
svg_data = svg_data.replace('stroke="#1f77b4"', 'stroke="url(#grad1)" filter="url(#dropshadow)"')
|
98 |
-
|
99 |
-
html_table = "<h3>Stock Prices Data</h3><div class='table-container'><table>"
|
100 |
-
html_table += "<thead><tr><th>Date</th>"
|
101 |
-
for stock_code in stock_prices.keys():
|
102 |
-
html_table += f"<th>{stock_code.upper()}</th>"
|
103 |
-
html_table += "</tr></thead><tbody>"
|
104 |
-
|
105 |
-
# Create a date range with only business days
|
106 |
-
all_dates = pd.date_range(start=min(df.index.min() for df in stock_prices.values()), end=pd.to_datetime('today'), freq='B')
|
107 |
-
all_dates = all_dates[::-1] # Reverse the order of dates
|
108 |
-
|
109 |
-
for date in all_dates:
|
110 |
-
html_table += f"<tr><td>{date.strftime('%Y-%m-%d')}</td>"
|
111 |
-
for stock_code in stock_prices.keys():
|
112 |
-
price = stock_prices[stock_code].get(date, None)
|
113 |
-
if price is not None:
|
114 |
-
html_table += f"<td>{price:,.2f}</td>"
|
115 |
-
else:
|
116 |
-
html_table += "<td>N/A</td>"
|
117 |
-
html_table += "</tr>"
|
118 |
-
|
119 |
-
html_table += "</tbody></table></div>"
|
120 |
-
|
121 |
-
graph_html = f'<h3>Relative Stock Prices Over the Last {days} Days</h3>{svg_data}'
|
122 |
-
return graph_html + html_table
|
123 |
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
# result = share_price_trend(stock_codes, days)
|
128 |
-
# print(result)
|
|
|
1 |
import io
|
|
|
|
|
2 |
import pandas as pd
|
3 |
+
import FinanceDataReader as fdr
|
4 |
+
import plotly.graph_objects as go
|
5 |
+
import gradio as gr
|
6 |
from concurrent.futures import ThreadPoolExecutor, as_completed
|
7 |
|
8 |
def get_stock_prices(stock_code, days):
|
|
|
33 |
print(f"<p style='color: red;'>Failed to fetch data for {stock_code}: {e}</p>")
|
34 |
|
35 |
if not stock_prices:
|
36 |
+
return "No data available for the provided stock codes."
|
37 |
|
38 |
+
fig = go.Figure()
|
|
|
39 |
|
|
|
40 |
for stock_code, prices in stock_prices.items():
|
41 |
relative_prices = prices / prices.iloc[0]
|
42 |
+
fig.add_trace(go.Scatter(
|
43 |
+
x=relative_prices.index,
|
44 |
+
y=relative_prices,
|
45 |
+
mode='lines',
|
46 |
+
name=stock_code.upper(),
|
47 |
+
hoverinfo='text',
|
48 |
+
hovertext=[f'{stock_code.upper()}: {date.strftime("%Y-%m-%d")}: {price:.2f}' for date, price in zip(prices.index, prices)]
|
49 |
+
))
|
50 |
|
51 |
+
fig.update_layout(
|
52 |
+
title=f'Relative Stock Prices Over the Last {days} Days',
|
53 |
+
xaxis_title='Date',
|
54 |
+
yaxis_title='Relative Price',
|
55 |
+
showlegend=True,
|
56 |
+
xaxis=dict(showline=False, showgrid=False),
|
57 |
+
yaxis=dict(showline=False, showgrid=False),
|
58 |
+
hovermode='x',
|
59 |
+
margin=dict(l=0, r=0, t=0, b=0), # Adjust margins to ensure the plot fits well
|
60 |
+
autosize=True
|
61 |
+
)
|
62 |
|
63 |
+
return fig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
+
def gradio_interface(stock_codes, days):
|
66 |
+
fig = share_price_trend(stock_codes, days)
|
67 |
+
return gr.Plot(fig)
|
|
|
|