|
|
|
@ -21,8 +21,8 @@ pd.options.plotting.backend = "plotly" |
|
|
|
|
|
|
|
|
|
# PARAMETERS |
|
|
|
|
CONFIGS = { |
|
|
|
|
"ENV": "development", |
|
|
|
|
"DEBUG": True, |
|
|
|
|
# "ENV": "development", |
|
|
|
|
# "DEBUG": True, |
|
|
|
|
"SECRET_KEY": os.urandom(30), # Set the secret key for session authentication |
|
|
|
|
"PERMANENT_SESSION_LIFETIME": timedelta(minutes=60) |
|
|
|
|
} |
|
|
|
@ -33,13 +33,13 @@ SQL_CONFIG = dict( |
|
|
|
|
port=os.getenv("PGPORT"), |
|
|
|
|
password=os.getenv("PGPASSWORD") |
|
|
|
|
) |
|
|
|
|
SQL_CONFIG = dict( |
|
|
|
|
database="railway", |
|
|
|
|
user="postgres", |
|
|
|
|
host="containers-us-west-103.railway.app", |
|
|
|
|
port="5913", |
|
|
|
|
password="gv5Mh7cPjCm9YTjAmsYD" |
|
|
|
|
) |
|
|
|
|
# SQL_CONFIG = dict( |
|
|
|
|
# database="railway", |
|
|
|
|
# user="postgres", |
|
|
|
|
# host="containers-us-west-103.railway.app", |
|
|
|
|
# port="5913", |
|
|
|
|
# password="gv5Mh7cPjCm9YTjAmsYD" |
|
|
|
|
# ) |
|
|
|
|
# SQL_CONFIG = {@ |
|
|
|
|
# 'database': "tpm", |
|
|
|
|
# 'user': "hsienchen", |
|
|
|
@ -251,11 +251,13 @@ def submit_stock_list(): |
|
|
|
|
## Query DB |
|
|
|
|
conn = psycopg2.connect(**SQL_CONFIG) |
|
|
|
|
port = get_stock(conn, stock_list, session['tw']) |
|
|
|
|
if len(port.index) > 750: |
|
|
|
|
port = port.iloc[-750:, :] |
|
|
|
|
if len(port.index) > 908: |
|
|
|
|
port = port.iloc[-908:, :] |
|
|
|
|
conn.close() |
|
|
|
|
port = port.iloc[::3, :] |
|
|
|
|
port = port/port.iloc[0, :] |
|
|
|
|
|
|
|
|
|
fig = port.plot(title='資產價格走勢', labels=dict(index="Date", value="Price", variable="Assets")) |
|
|
|
|
fig = port.plot(title='資產價格變化', labels=dict(index="Date", value="Price", variable="Assets")) |
|
|
|
|
fig['layout'] = {} |
|
|
|
|
|
|
|
|
|
# 序列化 |
|
|
|
@ -277,7 +279,7 @@ def buildPort(): |
|
|
|
|
if not 'tw' in session: |
|
|
|
|
return redirect(url_for('index')) |
|
|
|
|
# Stop frequently building strategy |
|
|
|
|
if time.time() - session['lastCreateTime'] < 10: |
|
|
|
|
if time.time() - session['lastCreateTime'] < 60: |
|
|
|
|
print("UNTIL: ", time.time()-session['lastCreateTime']) |
|
|
|
|
return '''<span>投資組合建立時間間隔(或與登入時間間隔)必須大於60秒!</span>''' |
|
|
|
|
# print('last_creation', time.time() - session['lastCreateTime']) |
|
|
|
@ -295,8 +297,8 @@ def buildPort(): |
|
|
|
|
|
|
|
|
|
# Opt Parameters |
|
|
|
|
comp = request.form.get('comp') |
|
|
|
|
# ts = int(request.form.get('ts')) |
|
|
|
|
ts = datetime.now().strftime("%Y-%m-%d, %H:%M:%S") |
|
|
|
|
ts = request.form.get('ts') |
|
|
|
|
# ts = datetime.now().strftime("%Y-%m-%d, %H:%M:%S") |
|
|
|
|
role = request.form.get('role') |
|
|
|
|
lookback = int(request.form.get('lookback')) |
|
|
|
|
backtest = int(request.form.get('frequency')) |
|
|
|
@ -305,8 +307,6 @@ def buildPort(): |
|
|
|
|
stock_list = json.loads(request.form.get('stockList')) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ratio=0.7 |
|
|
|
|
|
|
|
|
|
# Algorithm MVO |
|
|
|
|
print("-"*10) |
|
|
|
|
print("Enter Algorithms") |
|
|
|
@ -325,9 +325,9 @@ def buildPort(): |
|
|
|
|
n = len(port.index) |
|
|
|
|
if n < lookback+backtest+63: |
|
|
|
|
return f'''<span>投資組合無法建立,資料長度與所選參數不符。</span>''' |
|
|
|
|
elif n > 757+lookback: |
|
|
|
|
port = port.iloc[-(757+lookback):, :] |
|
|
|
|
market = market.iloc[-757:] |
|
|
|
|
elif n > 909+lookback: |
|
|
|
|
port = port.iloc[-(909+lookback):, :] |
|
|
|
|
market = market.iloc[-909:] |
|
|
|
|
else: |
|
|
|
|
market = market.iloc[lookback:] |
|
|
|
|
|
|
|
|
@ -368,23 +368,56 @@ def custom(): |
|
|
|
|
return render_template('custom.html', message='No') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/result') |
|
|
|
|
@app.route('/result', methods=['GET', 'POST']) |
|
|
|
|
def result(): |
|
|
|
|
if login_required(): |
|
|
|
|
pass |
|
|
|
|
else: |
|
|
|
|
flash('使用投組功能請先登入。', 'warning') |
|
|
|
|
return redirect(url_for('login')) |
|
|
|
|
|
|
|
|
|
sql="""select id, date, name, username, annual_ret, vol, annual_sr, mdd\ |
|
|
|
|
from strategy order by id desc limit 50;""" |
|
|
|
|
conn = psycopg2.connect(**SQL_CONFIG) |
|
|
|
|
with conn: |
|
|
|
|
with conn.cursor() as curs: |
|
|
|
|
curs.execute(sql) |
|
|
|
|
data= curs.fetchall() |
|
|
|
|
conn.close() |
|
|
|
|
return render_template('result.html', strategy_data=data) |
|
|
|
|
if request.method=='GET': |
|
|
|
|
conn = psycopg2.connect(**SQL_CONFIG) |
|
|
|
|
with conn: |
|
|
|
|
with conn.cursor() as curs: |
|
|
|
|
sql="select id, date, name, username, annual_ret, vol, annual_sr, mdd\ |
|
|
|
|
from strategy order by id desc limit 50" |
|
|
|
|
curs.execute(sql) |
|
|
|
|
data= curs.fetchall() |
|
|
|
|
conn.close() |
|
|
|
|
return render_template('result.html', strategy_data=data) |
|
|
|
|
elif request.method=='POST': |
|
|
|
|
role = request.form.get('role') |
|
|
|
|
comp = request.form.get('competition') |
|
|
|
|
if role in ['id', 'annual_ret', 'annual_sr', 'vol']: |
|
|
|
|
pass |
|
|
|
|
else: |
|
|
|
|
role='id' |
|
|
|
|
if comp == 'none': |
|
|
|
|
comp=None |
|
|
|
|
print("result", type(role), type(comp)) |
|
|
|
|
conn = psycopg2.connect(**SQL_CONFIG) |
|
|
|
|
with conn: |
|
|
|
|
with conn.cursor() as curs: |
|
|
|
|
if comp is None: |
|
|
|
|
if role is None: |
|
|
|
|
sql="select id, date, name, username, annual_ret, vol, annual_sr, mdd\ |
|
|
|
|
from strategy order by id desc limit 50" |
|
|
|
|
curs.execute(sql) |
|
|
|
|
elif role=='vol': |
|
|
|
|
sql=f"select id, date, name, username, annual_ret, vol, annual_sr, mdd\ |
|
|
|
|
from strategy order by {role} asc limit 50" |
|
|
|
|
curs.execute(sql) |
|
|
|
|
else: |
|
|
|
|
sql=f"select id, date, name, username, annual_ret, vol, annual_sr, mdd\ |
|
|
|
|
from strategy order by {role} desc limit 50" |
|
|
|
|
curs.execute(sql) |
|
|
|
|
else: |
|
|
|
|
sql=f"select id, date, name, username, annual_ret, vol, annual_sr, mdd\ |
|
|
|
|
from strategy where competition=%s order by {role} desc limit 50;" |
|
|
|
|
curs.execute(sql, (comp, )) |
|
|
|
|
data= curs.fetchall() |
|
|
|
|
conn.close() |
|
|
|
|
return render_template('result.html', strategy_data=data) |
|
|
|
|
|
|
|
|
|
@app.route('/result_view') |
|
|
|
|
def result_view(): |
|
|
|
@ -428,10 +461,10 @@ def result_view(): |
|
|
|
|
data['bar'] = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) |
|
|
|
|
return render_template('result_view.html', data=data) |
|
|
|
|
|
|
|
|
|
# handle login failed |
|
|
|
|
# @app.errorhandler(401) |
|
|
|
|
# def page_not_found(e): |
|
|
|
|
# return response('<p>Failed</p>') |
|
|
|
|
@app.errorhandler(404) |
|
|
|
|
def page_not_found(e): |
|
|
|
|
# note that we set the 404 status explicitly |
|
|
|
|
return render_template('404.html'), 404 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|