From 8efc5db4185a015fb6678748eb5dcb36051214d8 Mon Sep 17 00:00:00 2001 From: cuttlas90 Date: Wed, 24 Jul 2024 12:06:20 +0330 Subject: [PATCH 1/3] add technical page --- menu.py | 1 + pages/helper/gauge_chart.py | 70 ++++++++++++++++ pages/helper/query.py | 20 +++++ pages/helper/ta_metrics.py | 156 ++++++++++++++++++++++++++++++++++++ pages/technical.py | 117 +++++++++++++++++++++++++++ 5 files changed, 364 insertions(+) create mode 100644 pages/helper/gauge_chart.py create mode 100644 pages/helper/ta_metrics.py create mode 100644 pages/technical.py diff --git a/menu.py b/menu.py index 73da8b5..70c1654 100644 --- a/menu.py +++ b/menu.py @@ -9,5 +9,6 @@ def add_menu(): st.sidebar.page_link("pages/portfolio.py", label="تحلیل پورتفو", icon="📊") st.sidebar.page_link("pages/monte_carlo.py", label="مونته کارلو", icon="🧮") st.sidebar.page_link("pages/leveraged_funds.py", label="صندوقهای اهرمی", icon="🧮") + st.sidebar.page_link("pages/technical.py", label="تکنیکال", icon="📈") # st.sidebar.page_link("pages/simple_chart.py", label="نمودار ساده ماهانه", icon="📋") st.sidebar.page_link("pages/changelog.py", label="تازه ها", icon="💬") diff --git a/pages/helper/gauge_chart.py b/pages/helper/gauge_chart.py new file mode 100644 index 0000000..d840e45 --- /dev/null +++ b/pages/helper/gauge_chart.py @@ -0,0 +1,70 @@ +import streamlit as st +import pandas as pd +import altair as alt +from login import check_local_token +import numpy as np + +from pages.helper.query import Queries +from request import get_stock_monthly +# from slider import create_range_slider +from menu import add_menu +from finta import TA +from request import vasahm_query +import plotly.graph_objs as go +import streamlit.components.v1 as components + + + +def plot_gauge(current_value, min_value, max_value, chart_title, place): + plot_bgcolor = "#def" + quadrant_colors = [plot_bgcolor, "#2bad4e", "#85e043", "#eff229", "#f2a529", "#f25829"] + quadrant_text = ["", "Strong Buy", "Buy", "Neutral", "Sell", "Strong Sell"] + n_quadrants = len(quadrant_colors) - 1 + + hand_length = np.sqrt(2) / 4 + hand_angle = np.pi * (1 - (max(min_value, min(max_value, current_value)) - min_value) / (max_value - min_value)) + + fig = go.Figure( + data=[ + go.Pie( + values=[0.5] + (np.ones(n_quadrants) / 2 / n_quadrants).tolist(), + rotation=90, + hole=0.5, + marker_colors=quadrant_colors, + text=quadrant_text, + textinfo="text", + hoverinfo="skip", + ), + ], + layout=go.Layout( + showlegend=False, + margin=dict(b=0,t=10,l=10,r=10), + width=450, + height=450, + paper_bgcolor=plot_bgcolor, + annotations=[ + go.layout.Annotation( + text=f"{chart_title}", + x=0.5, xanchor="center", xref="paper", + y=0.25, yanchor="bottom", yref="paper", + showarrow=False, + ) + ], + shapes=[ + go.layout.Shape( + type="circle", + x0=0.48, x1=0.52, + y0=0.48, y1=0.52, + fillcolor="#333", + line_color="#333", + ), + go.layout.Shape( + type="line", + x0=0.5, x1=0.5 + hand_length * np.cos(hand_angle), + y0=0.5, y1=0.5 + hand_length * np.sin(hand_angle), + line=dict(color="#333", width=4) + ) + ] + ) + ) + place.plotly_chart(fig) \ No newline at end of file diff --git a/pages/helper/query.py b/pages/helper/query.py index 5b86ce6..c294591 100644 --- a/pages/helper/query.py +++ b/pages/helper/query.py @@ -767,6 +767,26 @@ def _dollar_query(self, text): INNER JOIN dollar ON ranked_dates.end_to_period::varchar = dollar.\"Jalali\" """ return query_string + + def price_query(self, dollar = False): + """get stock price""" + string = f"""select + date.miladi AS date, + \"openingPrice\" AS open, + \"maxPrice\" AS high, + \"minPrice\" AS low, + \"lastPrice\" AS close, + \"tradeVolume\" AS volume + from + public.stock_price + INNER JOIN stocks ON public.stock_price.stock_id = stocks.id + INNER JOIN date ON public.stock_price.\"tradeDate\" = date.jalali_3::TEXT + where + stocks.name = '{self.name}' + """ + if dollar: + string = self._dollar_query(string) + return string QUERY_MONTHLY_COMPARE = """WITH ranked_dates AS ( diff --git a/pages/helper/ta_metrics.py b/pages/helper/ta_metrics.py new file mode 100644 index 0000000..bda4bbb --- /dev/null +++ b/pages/helper/ta_metrics.py @@ -0,0 +1,156 @@ + +import streamlit as st +import pandas as pd +import altair as alt +from login import check_local_token +import numpy as np + +from pages.helper.gauge_chart import plot_gauge +from pages.helper.query import Queries +from request import get_stock_monthly +# from slider import create_range_slider +from menu import add_menu +from finta import TA +from request import vasahm_query +import plotly.graph_objs as go +import streamlit.components.v1 as components + + +def _update_guage(a, b, c, condition): + if condition in ["EMA","SMA","VAMA", "HMA"]: + if b >= c: + a = a +1 + else: + a=a-1 + return a + elif condition in ["RSI","STOCH"]: + if b >= 70.0: + a = a +1 + elif b <= 30.0: + a=a-1 + return a + elif condition in ["ADX"]: + if b >= 50.0: + a = a +1 + elif b <= 50.0: + a=a-1 + return a + elif condition == "CCI": + if b >= 100.0: + a = a -1 + elif b <= -100.0: + a=a+1 + return a + elif condition in ["AO","MOM", "MACD"]: + + if b >= 0.0: + a = a +1 + elif b <= 0.0: + a=a-1 + return a + elif condition in ["STOCHRSI"]: + if b >= 0.5: + a = a +1 + elif b <= 0.5: + a=a-1 + return a + elif condition in ["WILLIAMS"]: + if b >= -20.0: + a = a +1 + elif b <= -80.0: + a=a-1 + return a + +def add_ta_metrics(stock_data_history, data,metric_label, col, place, num, ind): + if ind == "EMA": + smas = TA.EMA(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'],ind) + return num + elif ind == "SMA": + smas = TA.SMA(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "VAMA": + smas = TA.VAMA(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "HMA": + smas = TA.HMA(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "RSI": + smas = TA.RSI(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "STOCH": + smas = TA.STOCH(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "CCI": + smas = TA.CCI(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "ADX": + smas = TA.ADX(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "AO": + smas = TA.AO(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "MOM": + smas = TA.MOM(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "MACD": + smas = TA.MACD(stock_data_history, data[0], data[1]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "STOCHRSI": + smas = TA.STOCHRSI(stock_data_history, data[0], data[1]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "WILLIAMS": + smas = TA.WILLIAMS(stock_data_history, data[0]) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + num=_update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "UO": + smas = TA.UO(stock_data_history) + sma_df = pd.DataFrame(smas) + st.write(sma_df.iloc[-1][col]) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + _update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + elif ind == "EBBP": + smas = TA.EBBP(stock_data_history) + sma_df = pd.DataFrame(smas) + place.metric(label=metric_label, value = int(sma_df.iloc[-1][col]), delta = int(sma_df.iloc[-1][col]-sma_df.iloc[-2][col])) + _update_guage(num, sma_df.iloc[-1][col], stock_data_history.iloc[-1]['close'], ind) + return num + \ No newline at end of file diff --git a/pages/technical.py b/pages/technical.py new file mode 100644 index 0000000..677330b --- /dev/null +++ b/pages/technical.py @@ -0,0 +1,117 @@ +"""Comapre monthly data in a customized way""" + +import streamlit as st +import pandas as pd +import altair as alt +from login import check_local_token +import numpy as np + +from pages.helper.gauge_chart import plot_gauge +from pages.helper.query import Queries +from pages.helper.ta_metrics import add_ta_metrics +from request import get_stock_monthly +# from slider import create_range_slider +from menu import add_menu +from finta import TA +from request import vasahm_query +import plotly.graph_objs as go +import streamlit.components.v1 as components + + + +st.set_page_config(layout='wide', + page_title="وسهم - داده های تکنیکال", + page_icon="./assets/favicon.ico", + initial_sidebar_state='collapsed') + + +with open( "style.css", encoding='UTF-8') as css: + st.markdown( f'' , unsafe_allow_html= True) +add_menu() +if "ver" in st.session_state: + st.sidebar.header(f'Vasahm DashBoard `{st.session_state.ver}`') + +df = pd.read_csv("data.csv").dropna() +list_of_name = df['name'].to_list() +if "stock" in st.query_params: + STOCK_INDEX = list_of_name.index(st.query_params.stock) +else: + STOCK_INDEX = 0 + +name = st.sidebar.selectbox("لیست سهام", options = list_of_name, index=STOCK_INDEX) +dollar_toggle = st.sidebar.toggle( + "نمایش به دلار", + help="با فعال کردن این گزینه تمامی مبالغ بر اساس دلار بازمحاسبه می گردد." + ) + + + +check_local_token() +if "token" in st.session_state: + queries = Queries(name) + + error, stock_data = vasahm_query(queries.price_query(dollar=dollar_toggle)) + if error: + st.error(stock_data, icon="🚨") + else: + components.iframe(f"https://chart.vasahm.com/?name={name}", height=500) + stock_data_history = pd.DataFrame(stock_data, columns=["date","open","high","low","close", "volume"]) + stock_data_history['date'] = pd.to_datetime(stock_data_history['date']) + stock_data_history['open'] = stock_data_history['open'].astype(int) + stock_data_history['high'] = stock_data_history['high'].astype(int) + stock_data_history['low'] = stock_data_history['low'].astype(int) + stock_data_history['close'] = stock_data_history['close'].astype(int) + stock_data_history['volume'] = stock_data_history['volume'].astype(int) + + data_to_plot = stock_data_history + data_to_plot.drop(["volume"], axis=1) + stock_data_history.set_index("date", inplace=True) + + col1, col2 = st.columns(2) + + move_gauge = col1.empty() + osi_gauge = col2.empty() + + current_value_moving = 0 + current_value_indicator = 0 + + + col1, col2 = st.columns(2) + + col11, col12, col13 = col1.columns(3) + + current_value_moving = add_ta_metrics(stock_data_history, [10],"EMA (10)", "10 period EMA", col11, current_value_moving, "EMA") + current_value_moving = add_ta_metrics(stock_data_history, [20], "EMA (20)", "20 period EMA", col12, current_value_moving, "EMA") + current_value_moving = add_ta_metrics(stock_data_history, [30], "EMA (30)", "30 period EMA", col13, current_value_moving, "EMA") + current_value_moving = add_ta_metrics(stock_data_history, [50], "EMA (50)", "50 period EMA", col11, current_value_moving, "EMA") + current_value_moving = add_ta_metrics(stock_data_history, [100], "EMA (100)", "100 period EMA", col12, current_value_moving, "EMA") + current_value_moving = add_ta_metrics(stock_data_history, [200], "EMA (200)", "200 period EMA", col13, current_value_moving, "EMA") + + current_value_moving = add_ta_metrics(stock_data_history, [10],"SMA (10)", "10 period SMA", col11, current_value_moving, "SMA") + current_value_moving = add_ta_metrics(stock_data_history, [20], "SMA (20)", "20 period SMA", col12, current_value_moving, "SMA") + current_value_moving = add_ta_metrics(stock_data_history, [30], "SMA (30)", "30 period SMA", col13, current_value_moving, "SMA") + current_value_moving = add_ta_metrics(stock_data_history, [50], "SMA (50)", "50 period SMA", col11, current_value_moving, "SMA") + current_value_moving = add_ta_metrics(stock_data_history, [100], "SMA (100)", "100 period SMA", col12, current_value_moving, "SMA") + current_value_moving = add_ta_metrics(stock_data_history, [200], "SMA (200)", "200 period SMA", col13, current_value_moving, "SMA") + + current_value_moving = add_ta_metrics(stock_data_history, [20], "VAMA (20)", "20 period VAMA", col11, current_value_moving, "VAMA") + current_value_moving = add_ta_metrics(stock_data_history, [9], "HMA (9)", "9 period HMA.", col12, current_value_moving, "HMA") + + col21, col22, col23 = col2.columns(3) + + current_value_indicator = add_ta_metrics(stock_data_history, [14], "RSI (14)", "14 period RSI", col21, current_value_indicator, "RSI") + current_value_indicator = add_ta_metrics(stock_data_history, [14], "STOCH (14)", "14 period STOCH %K", col22, current_value_indicator, "STOCH") + current_value_indicator = add_ta_metrics(stock_data_history, [14], "CCI (14)", "14 period CCI", col23, current_value_indicator, "CCI") + current_value_indicator = add_ta_metrics(stock_data_history, [14], "ADX (14)", "14 period ADX.", col21, current_value_indicator, "ADX") + current_value_indicator = add_ta_metrics(stock_data_history, [14], "AO (14)", "AO", col22, current_value_indicator, "AO") + current_value_indicator = add_ta_metrics(stock_data_history, [10], "MOM", "MOM", col23, current_value_indicator, "MOM") + current_value_indicator = add_ta_metrics(stock_data_history, [10,26], "MACD", "SIGNAL", col21, current_value_indicator, "MACD") + current_value_indicator = add_ta_metrics(stock_data_history, [14,14], "STOCHRSI", "14 period stochastic RSI.", col22, current_value_indicator, "STOCHRSI") + current_value_indicator = add_ta_metrics(stock_data_history, [14], "WILLIAMS", "14 Williams %R", col23, current_value_indicator, "WILLIAMS") + current_value_indicator = add_ta_metrics(stock_data_history, [], "EBBP BULL", "Bull.", col21, current_value_indicator, "EBBP") + current_value_indicator = add_ta_metrics(stock_data_history, [], "EBBP BEAR", "Bear.", col22, current_value_indicator, "EBBP") + current_value_indicator = add_ta_metrics(stock_data_history, [], "UO", 0, col23, current_value_indicator, "UO") + + + plot_gauge(current_value_moving, -15, 15, "Moving Averages Gauge", move_gauge) + plot_gauge(current_value_indicator, -9, 9, "Oscillators Gauge", osi_gauge) \ No newline at end of file From 6d35795bceb12151637a254b24108862f3bccb1f Mon Sep 17 00:00:00 2001 From: cuttlas90 Date: Wed, 24 Jul 2024 12:30:03 +0330 Subject: [PATCH 2/3] add social page --- menu.py | 3 ++- pages/helper/query.py | 15 +++++++++++ pages/social_page.py | 59 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 pages/social_page.py diff --git a/menu.py b/menu.py index 70c1654..b97c633 100644 --- a/menu.py +++ b/menu.py @@ -9,6 +9,7 @@ def add_menu(): st.sidebar.page_link("pages/portfolio.py", label="تحلیل پورتفو", icon="📊") st.sidebar.page_link("pages/monte_carlo.py", label="مونته کارلو", icon="🧮") st.sidebar.page_link("pages/leveraged_funds.py", label="صندوقهای اهرمی", icon="🧮") - st.sidebar.page_link("pages/technical.py", label="تکنیکال", icon="📈") + st.sidebar.page_link("pages/technical.py", label="اطلاعات تکنیکال", icon="📈") + st.sidebar.page_link("pages/social_page.py", label="اطلاعات رفتاری", icon="🌐") # st.sidebar.page_link("pages/simple_chart.py", label="نمودار ساده ماهانه", icon="📋") st.sidebar.page_link("pages/changelog.py", label="تازه ها", icon="💬") diff --git a/pages/helper/query.py b/pages/helper/query.py index c294591..a8df7a6 100644 --- a/pages/helper/query.py +++ b/pages/helper/query.py @@ -24,6 +24,21 @@ def get_stock_data(self): """ return string + def get_daily_social(self): + """return query to monthly sell value data""" + string = f"""select + number, + date + from + public.social_data + INNER JOIN stocks ON public.social_data.stock_id = stocks.id + where + stocks.name = '{self.name}' + LIMIT + 30 + + """ + return string def get_monthly_sell_value_data(self, dollar = False): """return query to monthly sell value data""" string = f"""select diff --git a/pages/social_page.py b/pages/social_page.py new file mode 100644 index 0000000..0a130a9 --- /dev/null +++ b/pages/social_page.py @@ -0,0 +1,59 @@ +"""Query Workbench.""" + +import streamlit as st +import pandas as pd +import altair as alt + +from login import check_local_token +from pages.helper.query import Queries +from request import vasahm_query +from menu import add_menu + + + +st.set_page_config(layout='wide', + page_title="وسهم - میزکار، دسترسی آزاد اطلاعات", + page_icon="./assets/favicon.ico", + initial_sidebar_state='expanded') + +with open( "style.css", encoding="UTF-8") as css: + st.markdown( f'' , unsafe_allow_html= True) + + +add_menu() + +df = pd.read_csv("data.csv").dropna() +list_of_name = df['name'].to_list() +if "stock" in st.query_params: + STOCK_INDEX = list_of_name.index(st.query_params.stock) +else: + STOCK_INDEX = 0 +name = st.sidebar.selectbox("لیست سهام", options = list_of_name, index=STOCK_INDEX) +selected_stock = df.iloc[df.loc[df['name'] == name].index[0]] + +if "ver" in st.session_state: + st.sidebar.header(f'Vasahm DashBoard `{st.session_state.ver}`') + +check_local_token() +if "token" in st.session_state: + + queries = Queries(name) + + error, stock_data = vasahm_query(queries.get_daily_social()) + if error: + st.error(stock_data, icon="🚨") + else: + if len(stock_data) > 0: + st.header("اقبال به سهم", divider='rainbow') + stock_data_history = pd.DataFrame(stock_data, columns=[ + "number", + "date"]) + # stock_data_history["date"] = stock_data_history[ + # "date"].astype(str) + + chart = alt.Chart(stock_data_history).mark_bar().encode( + # alt.Color('row_title:N', title="سرفصلها"), + alt.Y('number:Q', title="تعداد کامنت"), + alt.X('date:N',title="تاریخ") + ) + st.altair_chart(chart, use_container_width=True) From 952388cf7c4fca9c03d9b6118a37015104e81cd7 Mon Sep 17 00:00:00 2001 From: cuttlas90 Date: Wed, 24 Jul 2024 12:31:42 +0330 Subject: [PATCH 3/3] change log --- main.py | 2 +- pages/changelog.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 4bb8f2f..80a6fe6 100644 --- a/main.py +++ b/main.py @@ -19,7 +19,7 @@ page_title="وسهم", page_icon="./assets/favicon.ico", initial_sidebar_state='expanded') -st.session_state.ver = '0.1.8' +st.session_state.ver = '0.1.9' STREAMLIT_STATIC_PATH = Path(st.__path__[0]) / "static/static" CSS_PATH = STREAMLIT_STATIC_PATH / "media/" diff --git a/pages/changelog.py b/pages/changelog.py index 1b5751f..d724d50 100644 --- a/pages/changelog.py +++ b/pages/changelog.py @@ -14,6 +14,11 @@ if "ver" in st.session_state: st.sidebar.header(f'Vasahm DashBoard `{st.session_state.ver}`') +st.subheader('changelog: `version 0.1.9`', divider='rainbow') +st.markdown(''' + * افزودن صفحه اظلاعات تکنیکال + * افزودن صفحه اطلاعات رفتاری + * رفع باگهای کوچک''', unsafe_allow_html=False, help=None) st.subheader('changelog: `version 0.1.8`', divider='rainbow') st.markdown(''' * افزودن صفحه بررسی و مقایسه صندوقهای اهرمی