diff --git a/main.py b/main.py index fbce2af..aafa1b5 100644 --- a/main.py +++ b/main.py @@ -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 '''投資組合建立時間間隔(或與登入時間間隔)必須大於60秒!''' # 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'''投資組合無法建立,資料長度與所選參數不符。''' - 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('

Failed

') +@app.errorhandler(404) +def page_not_found(e): + # note that we set the 404 status explicitly + return render_template('404.html'), 404 diff --git a/portfolio_builder.py b/portfolio_builder.py index e2ca465..4fdaec0 100644 --- a/portfolio_builder.py +++ b/portfolio_builder.py @@ -49,7 +49,7 @@ class MVO(object): @staticmethod def sharpe_ratio(w, ret): cov = np.cov(ret.T) - print(cov.shape, w.shape) + # print(cov.shape, w.shape) retPort = ret@w # T-dimensional array stdPort = np.std(retPort) return np.mean(retPort)/stdPort @@ -138,7 +138,6 @@ class MVO(object): result = minimize(loss, init, method="SLSQP",\ options=opts, bounds=bnds, tol = None, jac = grad, constraints=cons) sol = result['x'] - print(sol) return np.round(sol, 2) diff --git a/sql_script/create_strategy.sql b/sql_script/create_strategy.sql index f3918ab..98c938c 100644 --- a/sql_script/create_strategy.sql +++ b/sql_script/create_strategy.sql @@ -1,7 +1,7 @@ DROP TABLE IF EXISTS strategy; CREATE TABLE strategy ( id SERIAL PRIMARY KEY, - date VARCHAR(24) NOT NULL, + date VARCHAR(64) NOT NULL, name VARCHAR(32) NOT NULL, username VARCHAR(32) NOT NULL, competition VARCHAR(32) NOT NULL, diff --git a/static/js/addStock.js b/static/js/addStock.js index c809e63..a5472e4 100644 --- a/static/js/addStock.js +++ b/static/js/addStock.js @@ -4,7 +4,7 @@ let currentList = []; const layout={'autosize': true, 'markers':true, 'title': {'text': ''}, 'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'rangeslider': {'visible': true}}, -'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'fixedrange': false}, +'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0]}, 'legend': {'yanchor': 'top', 'y': 1.1, 'xanchor': 'left', 'x': 0.01, 'orientation':'h'}, 'margin': {'l': 25, 'r': 5, 't': 10, 'b': 5}, } @@ -100,7 +100,7 @@ $sendPort.click(function(event) { method: 'POST', data: { name: $('input[name=portName]').val(), - ts: Date.now(), + ts: Date(Date.now()), comp: $('#competition').val(), lookback: $('#lookback').val(), frequency: $('#opt-frequency').val(), @@ -110,7 +110,7 @@ $sendPort.click(function(event) { stockList: JSON.stringify(stockList) }, success: function(response) { - console.log(response); + // console.log(response); // var res = JSON.parse(response); event.preventDefault(); // $('#modalTitle').text('完成建立') @@ -151,7 +151,7 @@ $submitBtn.click(function(event) { success: function(response) { $('#graph').html('') var graphs = JSON.parse(response); - console.log(graphs.data); + // console.log(graphs.data); Plotly.newPlot("graph", graphs.data, layout, {responsive: true}); // console.log(response.layout); diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..17151ef --- /dev/null +++ b/templates/404.html @@ -0,0 +1,14 @@ + + + + + + + Document + + +
+

404 Error

+
+ + \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index d892d4b..9603407 100644 --- a/templates/base.html +++ b/templates/base.html @@ -23,8 +23,8 @@ {% endblock %}