From 75850c39419469b4fb8ec5a9643fddb78775b1fc Mon Sep 17 00:00:00 2001 From: SeanChenTaipei Date: Thu, 2 Mar 2023 23:20:46 +0800 Subject: [PATCH] yeah --- main_old.py | 1347 -------------------------------------- t.html | 86 --- templates/base.html | 1 - templates/result.html | 2 +- templates/result_tw.html | 8 - templates/strategy.html | 164 ----- 6 files changed, 1 insertion(+), 1607 deletions(-) delete mode 100644 main_old.py delete mode 100644 t.html delete mode 100644 templates/result_tw.html delete mode 100644 templates/strategy.html diff --git a/main_old.py b/main_old.py deleted file mode 100644 index 709c0da..0000000 --- a/main_old.py +++ /dev/null @@ -1,1347 +0,0 @@ -# -*- coding: utf-8 -*- - -from flask import Flask, Blueprint, render_template, session, jsonify, request, redirect, url_for, flash, g, Markup, abort -# from flask_ipban import IpBan -from flask_login import login_required, current_user, login_user, logout_user -#from flask_environments import Environments -import sqlite3 -from werkzeug.security import generate_password_hash, check_password_hash -from datetime import datetime, timedelta -from dateutil.relativedelta import relativedelta -import os -import pytz -import re -import time -import json -import psycopg2 -import psycopg2.extras -from tickers_sorted import * -from tickers_sorted_tw import * -from black_list import black_list -from postgresql_config import * - -import numpy as np -import pandas as pd -import matplotlib.pyplot as plt - -import math -from cvxopt import matrix, solvers -from cvxopt.blas import dot -from cvxopt.solvers import qp - -import pickle - -UPLOAD_FOLDER = 'static/custom_data/' -ALLOWED_EXTENSIONS = {'csv'} -def allowed_file(filename): - return '.' in filename and \ - filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS - -main = Flask(__name__) - -# https://stackoverflow.com/questions/24222220/block-an-ip-address-from-accessing-my-flask-app-on-heroku -ip_ban_list = [] -@main.before_request -def block_method(): - ip = request.environ.get('REMOTE_ADDR') - if ip in ip_ban_list: - abort(403) - -main.config['SECRET_KEY'] = os.urandom(30) -main.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER - -from confidential_competitions import * -confidential_competitions_placeholder = ', '.join(['%s']*len(confidential_competitions_list)) - -# Source: https://uniwebsidad.com/libros/explore-flask/chapter-8/custom-filters -@main.template_filter('my_substitution') -def my_substitution(string): - return re.sub(r'@[a-zA-Z0-9_\-\.]+', r'', string) - -def ten_day_VaR(portfolio_value): - # 95% z value = 1.645 - z = 1.645 - return_value = portfolio_value.pct_change().shift(-1).dropna() - length = len(return_value) - daily_ret = return_value.mean() - daily_vol = return_value.std() - return -1*(daily_ret * 10 - daily_vol * (10**0.5) * z) - -# risk_free_rate = 0.00899 # U.S. 5 Year Treasury at 11:31 PM EDT, Jun 28, 2021 -risk_free_rate = 0 -def Linear_Reg(x,y): - ''' - input - x: market excess return, np.ndarray - y: portfolio excexx return, np.ndarray - - output - slope, intercept, R^2 - ''' - from sklearn import linear_model - import numpy - model = linear_model.LinearRegression(fit_intercept=True) - X = x[:,numpy.newaxis] - model.fit(X,y) - yhat = model.predict(X) - SSR = sum((y-yhat)**2) - SST = sum((y-numpy.mean(y))**2) - r_squared = 1 - (float(SSR))/SST - return model.coef_[0], model.intercept_, r_squared - # alpha = model.intercept_, beta = model.coef_[0] - -#env.filters['my_substitution'] = my_substitution - - - - -# def connect_db(): -# sql = sqlite3.connect('strategy.db', timeout=50) -# sql.row_factory = sqlite3.Row -# return sql -# -# def get_db(): -# if not hasattr(g, 'sqlite_db'): -# g.sqlite_db = connect_db() -# return g.sqlite_db -# -# @main.teardown_appcontext -# def close_db(error): -# if hasattr(g, 'sqlite_db'): -# g.sqlite_conn.close() - - -@main.route('/') -def index(): - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - - # Number of effective users - cur.execute('select count(b.a) as num_effective_users from (select min(strategy_id) as a from strategy group by author) as b') - num_effective_users = cur.fetchone()['num_effective_users'] - - # Number of effective strategies - cur.execute('select count(strategy_id) as num_effective_strategies from strategy where sharpe_ratio!=0') - num_effective_strategies = cur.fetchone()['num_effective_strategies'] - - cur.close() - conn.close() - - return render_template('index.html', num_effective_users=num_effective_users, num_effective_strategies=num_effective_strategies) - # return render_template('index_temp_0314.html') - - - - -@main.route('/create_strategy', methods=['GET', 'POST']) -def create_strategy(): - if not (session.get('USERNAME') and session['USERNAME']): - flash('使用此功能必須先登入。', 'danger') - return redirect('/login') - if session['USERNAME'] in black_list: - flash('我們已經暫停您建立策略的權利,有疑問請洽finteck@my.nthu.edu.tw', 'danger') - return redirect('/') - print('last_creation_time: ', session['last_creation_time']) - if time.time() - session['last_creation_time'] < 30: - flash('每兩次建立策略須間隔30秒', 'danger') - return redirect('/') - - if request.method == 'GET': - tw = request.values.get('tw') - tw_digit = 1 if tw=='true' else 0 if tw=='false' else None - - if request.method == 'POST': - strategy_name = request.form['strategy_name'] - create_date = datetime.strftime(datetime.now() + timedelta(hours=8), '%Y/%m/%d %H:%M:%S.%f') - session['last_creation_time'] = time.time() - - if strategy_name == '': - flash('請取一個名字', 'danger') - return render_template('create_strategy.html', asset_candidates=asset_candidates if tw=='false' else asset_candidates_tw if tw=='true' else None, tw=tw) - competition = request.form['competition'] - tw = request.form['tw'] - tw_digit = 1 if tw=='true' else 0 if tw=='false' else None - tickers = sorted(list(set(request.form.getlist('asset_ticker')))) - print('The list of assets: ', tickers) - - - # Turn off progress printing - solvers.options['show_progress'] = False - - start_dates = [ datetime(y, m, 1) for y in range(2015, datetime.now().year+1) - for m in [1, 4, 7, 10] - if datetime(y, m, 1)=start) & (all_data['Date']<=end) ] - data.set_index('Date', inplace=True) - data = data['Adj Close'] - return data - - - portfolio_value = pd.Series([100]) - optimal_weights = None - hist_return_series = pd.DataFrame(columns=['quarter', 'quarterly_returns']) - - index_returns_full = pd.Series() - portfolio_returns_full = pd.Series() - - for i in range(len(start_dates)-3): - - ### Take 6 months to backtest ### - - start = start_dates[i] - end = start_dates[i+2] - - data = pd.DataFrame({ ticker: stockpri(ticker, start, end) for ticker in tickers }) - data = data.dropna() - - returns = data.pct_change() + 1 - returns = returns.dropna() - log_returns = np.log(data.pct_change() + 1) - log_returns = log_returns.dropna() - - if log_returns.empty: - continue - - mu = np.exp(log_returns.mean()*252).values - # Markowitz frontier - profit = np.linspace(np.amin(mu), np.amax(mu), 100) - frontier = [] - w = [] - if len(tickers) >= 3: - for p in profit: - # Problem data. - n = len(tickers) - S = matrix(log_returns.cov().values*252) - pbar = matrix(0.0, (n,1)) - # Gx <= h - G = matrix(0.0, (2*n,n)) - G[::(2*n+1)] = 1.0 - G[n::(2*n+1)] = -1.0 - # h = matrix(1.0, (2*n,1)) - h = matrix(np.concatenate((0.5*np.ones((n,1)), -0.03*np.ones((n,1))), axis=0)) - A = matrix(np.concatenate((np.ones((1,n)), mu.reshape((1,n))), axis=0)) - b = matrix([1, p], (2, 1)) - - # Compute trade-off. - res = qp(S, -pbar, G, h, A, b) - - if res['status'] == 'optimal': - res_weight = res['x'] - s = math.sqrt(dot(res_weight, S*res_weight)) - frontier.append(np.array([p, s])) - w.append(res_weight) - elif len(tickers) == 2: - for p in profit: - S = log_returns.cov().values*252 - res_weight = [1 - (p-mu[0])/(mu[1]-mu[0]), (p-mu[0])/(mu[1]-mu[0])] - if (res_weight[0] < 0.03) or (res_weight[0] > 0.97): - continue - s = math.sqrt(np.matmul(res_weight, np.matmul(S, np.transpose(res_weight)))) - frontier.append(np.array([p, s])) - w.append(res_weight) - elif len(tickers) == 1: - res_weight = [1] - w.append(res_weight) - frontier.append(np.array([1, 1])) - - - frontier = np.array(frontier) - if frontier.shape == (0,): - continue - x = np.array(frontier[:, 0]) - y = np.array(frontier[:, 1]) - - frontier_sharpe_ratios = np.divide(x-1, y) - optimal_portfolio_index = np.argmax(frontier_sharpe_ratios) - optimal_weights = w[optimal_portfolio_index] - - - ### paper trade on the next three months ### - - start = start_dates[i+2] - end = start_dates[i+3] - - if tw=='true': - index_ticker = '0050.TW' - elif tw=='false': - index_ticker = 'SPY' - - data = pd.DataFrame({ ticker: stockpri(ticker, start, end) for ticker in tickers }) - data['market'] = stockpri(index_ticker, start, end) - data = data.dropna() - - returns = data.pct_change() + 1 - returns = returns.dropna() - log_returns = np.log(data.pct_change() + 1) - log_returns = log_returns.dropna() - - index_returns_3_months = returns['market'] - data = data.drop(columns=['market']) - returns = returns.drop(columns=['market']) - log_returns = log_returns.drop(columns=['market']) - portfolio_returns_3_months = pd.Series(np.dot(returns, optimal_weights).flatten()) - - index_returns_full = index_returns_full.append(index_returns_3_months, ignore_index=True) - portfolio_returns_full = portfolio_returns_full.append(portfolio_returns_3_months, ignore_index=True) - - portfolio_cum_returns = np.dot(returns, optimal_weights).cumprod() - portfolio_value_new_window = portfolio_value.iloc[-1].item() * pd.Series(portfolio_cum_returns) - portfolio_value_new_window.index = pd.to_datetime(returns.index, format='%Y-%m-%d') - portfolio_value = portfolio_value.append(portfolio_value_new_window) - - # produce quarterly return - hist_return_series.loc[len(hist_return_series)] = [str(start.year)+'Q'+str((start.month+2)//3), portfolio_cum_returns[-1]-1] - - if optimal_weights == None: - sharpe_ratio = avg_annual_return = annual_volatility = max_drawdown = alpha = beta = r_squared = ten_day_var = 0 - optimal_weights = [0, ]*len(tickers) - hist_returns = None - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""insert into strategy (strategy_name, - author, - create_date, - sharpe_ratio, - return, - volatility, - max_drawdown, - tw, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var) - values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) returning strategy_id;""", - (strategy_name, - session['USERNAME'], - create_date, - sharpe_ratio, - avg_annual_return, - annual_volatility, - max_drawdown, - tw_digit, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var - ) ) - strategy_id = cur.fetchone()[0] - conn.commit() - - # record the list of tickers into database - # strategy_id = cur.execute('select * from strategy where create_date=?', [create_date]).fetchone()['strategy_id'] - for i in range(len(tickers)): - cur.execute('insert into assets_in_strategy (strategy_id, asset_ticker, weight) values (%s, %s, %s)', - (strategy_id, tickers[i], optimal_weights[i])) - conn.commit() - - cur.close() - conn.close() - - print('Strategy_id ' + str(strategy_id) + ' optimization fails.') - flash('無資料或無法畫出馬可維茲邊界,請換一個組合', 'danger') - return render_template('create_strategy.html', asset_candidates=asset_candidates if tw=='false' else asset_candidates_tw if tw=='true' else None, tw=tw) - - avg_annual_return = np.exp(np.log(portfolio_value.pct_change() + 1).mean() * 252) - 1 - annual_volatility = portfolio_value.pct_change().std() * math.sqrt(252) - sharpe_ratio = avg_annual_return/annual_volatility - max_drawdown = - np.amin(np.divide(portfolio_value, np.maximum.accumulate(portfolio_value)) - 1) - ten_day_var = ten_day_VaR(portfolio_value) - beta, alpha, r_squared = Linear_Reg(index_returns_full.to_numpy().flatten() - risk_free_rate, - portfolio_returns_full.to_numpy().flatten() - risk_free_rate) - - print('Sharpe ratio: ', sharpe_ratio, ', Return: ', avg_annual_return, ', Volatility: ', annual_volatility, ', Maximum Drawdown: ', max_drawdown) - - # hist_return_series.set_index('quarter', inplace=True) - hist_returns = pickle.dumps(hist_return_series) - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""insert into strategy (strategy_name, - author, - create_date, - sharpe_ratio, - return, - volatility, - max_drawdown, - tw, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var) - values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) returning strategy_id;""", - (strategy_name, - session['USERNAME'], - create_date, - sharpe_ratio, - avg_annual_return, - annual_volatility, - max_drawdown, - tw_digit, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var - ) ) - strategy_id = cur.fetchone()[0] - conn.commit() - - # record the list of tickers into database - # strategy_id = cur.execute('select * from strategy where create_date=?', [create_date]).fetchone()['strategy_id'] - for i in range(len(tickers)): - cur.execute('insert into assets_in_strategy (strategy_id, asset_ticker, weight) values (%s, %s, %s)', - (strategy_id, tickers[i], optimal_weights[i])) - conn.commit() - - cur.close() - conn.close() - - # fig, ax = plt.subplots() - # hist_return_series.hist(column='quarterly_returns', by='quarter', ax=ax) - hist_return_plot = hist_return_series.plot.bar(x='quarter', y='quarterly_returns').get_figure() - plt.tight_layout() - # plt.xticks(rotation=45) - hist_return_plot.savefig('static/img/quarterly_returns/'+str(strategy_id)+'.png') - plt.close() - - print(portfolio_value.head()) - print(portfolio_value.tail()) - plt.xticks(rotation=90) - # plt.tight_layout() - plt.plot(portfolio_value.iloc[1:]) - plt.savefig('static/img/portfolio_values/'+str(strategy_id)+'.png', bbox_inches='tight') - plt.close() - print('Strategy_id ' + str(strategy_id) + ' optimization succeeds.') - flash(Markup('回測已完成,詳情請點這裡查看。'), 'success') - return render_template('create_strategy.html', asset_candidates=asset_candidates if tw=='false' else asset_candidates_tw if tw=='true' else None, tw=tw) - - -@main.route('/create_strategy_upload', methods=['GET', 'POST']) -def create_strategy_upload(): - if not (session.get('USERNAME') and session['USERNAME']): - flash('使用此功能必須先登入。', 'danger') - return redirect('/login') - if session['USERNAME'] in black_list: - flash('我們已經暫停您建立策略的權利,有疑問請洽finteck@my.nthu.edu.tw', 'danger') - return redirect('/') - print('last_creation_time: ', session['last_creation_time']) - if time.time() - session['last_creation_time'] < 30: - flash('每兩次建立策略須間隔30秒', 'danger') - return redirect('/') - - if request.method == 'POST': - strategy_name = request.form['strategy_name'] - create_date = datetime.strftime(datetime.now() + timedelta(hours=8), '%Y/%m/%d %H:%M:%S.%f') - session['last_creation_time'] = time.time() - - if strategy_name == '': - flash('請取一個名字', 'danger') - return render_template('create_strategy_upload.html') - - f = request.files['fileToUpload'] - filename = create_date.replace('/', '').replace(' ', '').replace(':', '').replace('.', '') + '.csv' - f.save(os.path.join(main.config['UPLOAD_FOLDER'], filename)) - - all_data = pd.read_csv(main.config['UPLOAD_FOLDER'] + filename) - all_data['Date'] = pd.to_datetime(all_data['Date'], format='%Y-%m-%d') - - tickers = list(all_data.columns) - tickers.remove('Date') - print('The list of assets: ', tickers) - - competition = request.form['competition'] - - - # Turn off progress printing - solvers.options['show_progress'] = False - - - def stockpri(ticker, start, end): - data = all_data.loc[start:end, ['Date', ticker]] - data.set_index('Date', inplace=True) - data = data[ticker] - return data - - - portfolio_value = pd.Series([100]) - optimal_weights = None - hist_return_series = pd.DataFrame(columns=['quarter', 'quarterly_returns']) - - start_dates = list(np.arange(0, len(all_data), 63)) + [len(all_data)-1] - - - for i in range(len(start_dates)-3): - - ### Take 6 months to backtest ### - - start = start_dates[i] - end = start_dates[i+2]+1 - - data = pd.DataFrame({ ticker: stockpri(ticker, start, end) for ticker in tickers }) - data = data.dropna() - - returns = data.pct_change() + 1 - returns = returns.dropna() - log_returns = np.log(data.pct_change() + 1) - log_returns = log_returns.dropna() - - if log_returns.empty: - continue - - mu = np.exp(log_returns.mean()*252).values - # Markowitz frontier - profit = np.linspace(np.amin(mu), np.amax(mu), 100) - frontier = [] - w = [] - if len(tickers) >= 3: - for p in profit: - # Problem data. - n = len(tickers) - S = matrix(log_returns.cov().values*252) - pbar = matrix(0.0, (n,1)) - # Gx <= h - G = matrix(0.0, (2*n,n)) - G[::(2*n+1)] = 1.0 - G[n::(2*n+1)] = -1.0 - # h = matrix(1.0, (2*n,1)) - h = matrix(np.concatenate((0.5*np.ones((n,1)), -0.03*np.ones((n,1))), axis=0)) - A = matrix(np.concatenate((np.ones((1,n)), mu.reshape((1,n))), axis=0)) - b = matrix([1, p], (2, 1)) - - # Compute trade-off. - res = qp(S, -pbar, G, h, A, b) - - if res['status'] == 'optimal': - res_weight = res['x'] - s = math.sqrt(dot(res_weight, S*res_weight)) - frontier.append(np.array([p, s])) - w.append(res_weight) - elif len(tickers) == 2: - for p in profit: - S = log_returns.cov().values*252 - res_weight = [1 - (p-mu[0])/(mu[1]-mu[0]), (p-mu[0])/(mu[1]-mu[0])] - if (res_weight[0] < 0.03) or (res_weight[0] > 0.97): - continue - s = math.sqrt(np.matmul(res_weight, np.matmul(S, np.transpose(res_weight)))) - frontier.append(np.array([p, s])) - w.append(res_weight) - - - frontier = np.array(frontier) - if frontier.shape == (0,): - continue - x = np.array(frontier[:, 0]) - y = np.array(frontier[:, 1]) - - frontier_sharpe_ratios = np.divide(x-1, y) - optimal_portfolio_index = np.argmax(frontier_sharpe_ratios) - optimal_weights = w[optimal_portfolio_index] - - - ### paper trade on the next three months ### - - start = start_dates[i+2] - end = start_dates[i+3]+1 - - data = pd.DataFrame({ ticker: stockpri(ticker, start, end) for ticker in tickers }) - data = data.dropna() - - returns = data.pct_change() + 1 - returns = returns.dropna() - log_returns = np.log(data.pct_change() + 1) - log_returns = log_returns.dropna() - - - portfolio_cum_returns = np.dot(returns, optimal_weights).cumprod() - portfolio_value_new_window = portfolio_value.iloc[-1].item() * pd.Series(portfolio_cum_returns) - portfolio_value_new_window.index = pd.to_datetime(returns.index, format='%Y-%m-%d') - portfolio_value = portfolio_value.append(portfolio_value_new_window) - # portfolio_value.append(portfolio_value_new_window) - - # produce quarterly return - hist_return_series.loc[len(hist_return_series)] = [str(start), portfolio_cum_returns[-1]-1] - - - if len(tickers) == 1: - optimal_weights = [1] - portfolio_value = stockpri(tickers[0], 0, len(all_data)) - for i in range(len(start_dates)-1): - hist_return_series.loc[i] = [ str(start_dates[i]), portfolio_value[start_dates[i+1]] - portfolio_value[start_dates[i]] ] - - if optimal_weights == None: - sharpe_ratio = avg_annual_return = annual_volatility = max_drawdown = ten_day_var = 0 - optimal_weights = [0, ]*len(tickers) - hist_returns = None - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""insert into strategy (strategy_name, - author, - create_date, - sharpe_ratio, - return, - volatility, - max_drawdown, - tw, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var) - values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) returning strategy_id;""", - (strategy_name, - session['USERNAME'], - create_date, - sharpe_ratio, - avg_annual_return, - annual_volatility, - max_drawdown, - 0, # tw_digit, - competition, - hist_returns, - 0, # alpha, - 0, # beta, - 0, # r_squared, - ten_day_var - ) ) - strategy_id = cur.fetchone()[0] - conn.commit() - - # record the list of tickers into database - # strategy_id = cur.execute('select * from strategy where create_date=?', [create_date]).fetchone()['strategy_id'] - for i in range(len(tickers)): - cur.execute('insert into assets_in_strategy (strategy_id, asset_ticker, weight) values (%s, %s, %s)', - (strategy_id, tickers[i], optimal_weights[i])) - conn.commit() - - cur.close() - conn.close() - print('Strategy_id ' + str(strategy_id) + ' optimization fails.') - flash('無資料或無法畫出馬可維茲邊界,請換一個組合', 'danger') - return render_template('create_strategy_upload.html') - - avg_annual_return = np.exp(np.log(portfolio_value.pct_change() + 1).mean() * 252) - 1 - annual_volatility = portfolio_value.pct_change().std() * math.sqrt(252) - sharpe_ratio = avg_annual_return/annual_volatility - max_drawdown = - np.amin(np.divide(portfolio_value, np.maximum.accumulate(portfolio_value)) - 1) - ten_day_var = ten_day_VaR(portfolio_value) - - print('Sharpe ratio: ', sharpe_ratio, ', Return: ', avg_annual_return, ', Volatility: ', annual_volatility, ', Maximum Drawdown: ', max_drawdown) - - # hist_return_series.set_index('quarter', inplace=True) - hist_returns = pickle.dumps(hist_return_series) - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""insert into strategy (strategy_name, - author, - create_date, - sharpe_ratio, - return, - volatility, - max_drawdown, - tw, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) returning strategy_id;""", - (strategy_name, - session['USERNAME'], - create_date, - sharpe_ratio, - avg_annual_return, - annual_volatility, - max_drawdown, - 0, # tw_digit, - competition, - hist_returns, - 0, # alpha, - 0, # beta, - 0, # r_squared, - ten_day_var - ) ) - strategy_id = cur.fetchone()[0] - conn.commit() - - # record the list of tickers into database - # strategy_id = cur.execute('select * from strategy where create_date=%s', (create_date,)).fetchone()['strategy_id'] - for i in range(len(tickers)): - cur.execute('insert into assets_in_strategy (strategy_id, asset_ticker, weight) values (%s, %s, %s)', - (strategy_id, tickers[i], optimal_weights[i])) - conn.commit() - - cur.close() - conn.close() - - # fig, ax = plt.subplots() - # hist_return_series.hist(column='quarterly_returns', by='quarter', ax=ax) - hist_return_plot = hist_return_series.plot.bar(x='quarter', y='quarterly_returns').get_figure() - plt.tight_layout() - hist_return_plot.savefig('static/img/quarterly_returns/'+str(strategy_id)+'.png') - plt.close() - - print(portfolio_value.head()) - print(portfolio_value.tail()) - plt.xticks(rotation=90) - # plt.tight_layout() - plt.plot(portfolio_value.iloc[1:]) - plt.savefig('static/img/portfolio_values/'+str(strategy_id)+'.png', bbox_inches='tight') - plt.close() - print('Strategy_id ' + str(strategy_id) + ' optimization succeeds.') - flash(Markup('回測已完成,詳情請點這裡查看。'), 'success') - return render_template('create_strategy_upload.html') - - - -@main.route('/create_strategy_topic', methods=['GET', 'POST']) -def create_strategy_topic(): - if not (session.get('USERNAME') and session['USERNAME']): - flash('使用此功能必須先登入。', 'danger') - return redirect('/login') - if session['USERNAME'] in black_list: - flash('我們已經暫停您建立策略的權利,有疑問請洽finteck@my.nthu.edu.tw', 'danger') - return redirect('/') - print('last_creation_time: ', session['last_creation_time']) - if time.time() - session['last_creation_time'] < 30: - flash('每兩次建立策略須間隔30秒', 'danger') - return redirect('/') - - if request.method == 'POST': - strategy_name = request.form['strategy_name'] - create_date = datetime.strftime(datetime.now() + timedelta(hours=8), '%Y/%m/%d %H:%M:%S.%f') - session['last_creation_time'] = time.time() - - if strategy_name == '': - flash('請取一個名字', 'danger') - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""select * from strategy where competition='topic' order by strategy_id desc""") - sql_results = cur.fetchall() - cur.close() - conn.close() - return render_template('create_strategy_topic.html', topic_results=sql_results) - - f = request.files['fileToUpload'] - filename = create_date.replace('/', '').replace(' ', '').replace(':', '').replace('.', '') + '.csv' - f.save(os.path.join(main.config['UPLOAD_FOLDER'], filename)) - - all_data = pd.read_csv(main.config['UPLOAD_FOLDER'] + filename) - all_data['Date'] = pd.to_datetime(all_data['Date'], format='%Y-%m-%d') - - tickers = list(all_data.columns) - tickers.remove('Date') - print('The list of assets: ', tickers) - - competition = request.form['competition'] - - - # Turn off progress printing - solvers.options['show_progress'] = False - - - def stockpri(ticker, start, end): - data = all_data.loc[start:end, ['Date', ticker]] - data.set_index('Date', inplace=True) - data = data[ticker] - return data - - - portfolio_value = pd.Series([100]) - optimal_weights = None - hist_return_series = pd.DataFrame(columns=['month', 'monthly_returns']) - - start_dates = list(np.arange(0, len(all_data), 21)) + [len(all_data)-1] - - - for i in range(len(start_dates)-3): - - ### Take 6 months to backtest ### - - start = start_dates[i] - end = start_dates[i+2]+1 - - data = pd.DataFrame({ ticker: stockpri(ticker, start, end) for ticker in tickers }) - data = data.dropna() - - returns = data.pct_change() + 1 - returns = returns.dropna() - log_returns = np.log(data.pct_change() + 1) - log_returns = log_returns.dropna() - - if log_returns.empty: - continue - - mu = np.exp(log_returns.mean()*252).values - # Markowitz frontier - profit = np.linspace(np.amin(mu), np.amax(mu), 100) - frontier = [] - w = [] - if len(tickers) >= 3: - for p in profit: - # Problem data. - n = len(tickers) - S = matrix(log_returns.cov().values*252) - pbar = matrix(0.0, (n,1)) - # Gx <= h - G = matrix(0.0, (2*n,n)) - G[::(2*n+1)] = 1.0 - G[n::(2*n+1)] = -1.0 - # h = matrix(1.0, (2*n,1)) - h = matrix(np.concatenate((0.5*np.ones((n,1)), -0.03*np.ones((n,1))), axis=0)) - A = matrix(np.concatenate((np.ones((1,n)), mu.reshape((1,n))), axis=0)) - b = matrix([1, p], (2, 1)) - - # Compute trade-off. - res = qp(S, -pbar, G, h, A, b) - - if res['status'] == 'optimal': - res_weight = res['x'] - s = math.sqrt(dot(res_weight, S*res_weight)) - frontier.append(np.array([p, s])) - w.append(res_weight) - elif len(tickers) == 2: - for p in profit: - S = log_returns.cov().values*252 - res_weight = [1 - (p-mu[0])/(mu[1]-mu[0]), (p-mu[0])/(mu[1]-mu[0])] - if (res_weight[0] < 0.03) or (res_weight[0] > 0.97): - continue - s = math.sqrt(np.matmul(res_weight, np.matmul(S, np.transpose(res_weight)))) - frontier.append(np.array([p, s])) - w.append(res_weight) - - - frontier = np.array(frontier) - if frontier.shape == (0,): - continue - x = np.array(frontier[:, 0]) - y = np.array(frontier[:, 1]) - - frontier_sharpe_ratios = np.divide(x-1, y) - optimal_portfolio_index = np.argmax(frontier_sharpe_ratios) - optimal_weights = w[optimal_portfolio_index] - - - ### paper trade on the next three months ### - - start = start_dates[i+2] - end = start_dates[i+3]+1 - - data = pd.DataFrame({ ticker: stockpri(ticker, start, end) for ticker in tickers }) - data = data.dropna() - - returns = data.pct_change() + 1 - returns = returns.dropna() - log_returns = np.log(data.pct_change() + 1) - log_returns = log_returns.dropna() - - - portfolio_cum_returns = np.dot(returns, optimal_weights).cumprod() - portfolio_value_new_window = portfolio_value.iloc[-1].item() * pd.Series(portfolio_cum_returns) - portfolio_value_new_window.index = pd.to_datetime(returns.index, format='%Y-%m-%d') - portfolio_value = portfolio_value.append(portfolio_value_new_window) - - # produce monthly return - hist_return_series.loc[len(hist_return_series)] = [str(start), portfolio_cum_returns[-1]-1] - - if optimal_weights == None: - sharpe_ratio = avg_annual_return = annual_volatility = max_drawdown = ten_day_var = 0 - optimal_weights = [0, ]*len(tickers) - hist_returns = None - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""insert into strategy (strategy_name, - author, - create_date, - explanation, - sharpe_ratio, - return, - volatility, - max_drawdown, - tw, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var) - values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) returning strategy_id;""", - (strategy_name, - session['USERNAME'], - create_date, - "", #explanation - sharpe_ratio, - avg_annual_return, - annual_volatility, - max_drawdown, - 0, # tw_digit, - competition, - hist_returns, - 0, # alpha, - 0, # beta, - 0, # r_squared, - ten_day_var - ) ) - strategy_id = cur.fetchone()[0] - conn.commit() - - # record the list of tickers into database - # strategy_id = cur.execute('select * from strategy where create_date=?', [create_date]).fetchone()['strategy_id'] - for i in range(len(tickers)): - cur.execute('insert into assets_in_strategy (strategy_id, asset_ticker, weight) values (%s, %s, %s)', - (strategy_id, tickers[i], optimal_weights[i])) - conn.commit() - - cur.close() - conn.close() - print('Strategy_id ' + str(strategy_id) + ' optimization fails.') - flash('無資料或無法畫出馬可維茲邊界,請換一個組合', 'danger') - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""select * from strategy where competition='topic' order by strategy_id desc""") - sql_results = cur.fetchall() - cur.close() - conn.close() - return render_template('create_strategy_topic.html', topic_results=sql_results) - - avg_annual_return = np.exp(np.log(portfolio_value.pct_change() + 1).mean() * 252) - 1 - annual_volatility = portfolio_value.pct_change().std() * math.sqrt(252) - sharpe_ratio = avg_annual_return/annual_volatility - max_drawdown = - np.amin(np.divide(portfolio_value, np.maximum.accumulate(portfolio_value)) - 1) - ten_day_var = ten_day_VaR(portfolio_value) - - print('Sharpe ratio: ', sharpe_ratio, ', Return: ', avg_annual_return, ', Volatility: ', annual_volatility, ', Maximum Drawdown: ', max_drawdown) - - # hist_return_series.set_index('month', inplace=True) - hist_returns = pickle.dumps(hist_return_series) - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""insert into strategy (strategy_name, - author, - create_date, - explanation, - sharpe_ratio, - return, - volatility, - max_drawdown, - tw, - competition, - hist_returns, - alpha, - beta, - r_squared, - ten_day_var) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) returning strategy_id;""", - (strategy_name, - session['USERNAME'], - create_date, - "", #explanation - sharpe_ratio, - avg_annual_return, - annual_volatility, - max_drawdown, - 0, # tw_digit, - competition, - hist_returns, - 0, # alpha, - 0, # beta, - 0, # r_squared, - ten_day_var - ) ) - strategy_id = cur.fetchone()[0] - conn.commit() - - # record the list of tickers into database - # strategy_id = cur.execute('select * from strategy where create_date=%s', (create_date,)).fetchone()['strategy_id'] - for i in range(len(tickers)): - cur.execute('insert into assets_in_strategy (strategy_id, asset_ticker, weight) values (%s, %s, %s)', - (strategy_id, tickers[i], optimal_weights[i])) - conn.commit() - - cur.close() - conn.close() - - # fig, ax = plt.subplots() - # hist_return_series.hist(column='monthly_returns', by='month', ax=ax) - hist_return_plot = hist_return_series.plot.bar(x='month', y='monthly_returns').get_figure() - plt.tight_layout() - hist_return_plot.savefig('static/img/monthly_returns/'+str(strategy_id)+'.png') - plt.close() - - print(portfolio_value.head()) - print(portfolio_value.tail()) - plt.xticks(rotation=90) - # plt.tight_layout() - plt.plot(portfolio_value.iloc[1:]) - plt.savefig('static/img/portfolio_values/'+str(strategy_id)+'.png', bbox_inches='tight') - plt.close() - print('Strategy_id ' + str(strategy_id) + ' optimization succeeds.') - flash(Markup('回測已完成,詳情請點這裡查看。'), 'success') - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""select * from strategy where competition in ('topic_high_sharpe', 'topic_high_esg', 'topic_high_return', 'topic_high_volume') order by strategy_id desc""") - sql_results = cur.fetchall() - cur.close() - conn.close() - return render_template('create_strategy_topic.html', topic_results=sql_results) - - -@main.route('/login') -def login(): - return render_template('login.html') - - -@main.route('/login', methods=['POST']) -def login_post(): - password = request.form.get('password') - username = request.form.get('username') - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute('select * from users where username=%s', (username,)) - sql_result = cur.fetchone() - cur.close() - conn.close() - - if (not sql_result) or (not check_password_hash(sql_result['password'], password)): - flash('使用者代號不對或密碼不對,請再試一次。', 'danger') - return redirect('/login') - - print(sql_result['username'], sql_result['user_id']) - session['login'] = True - session['user_id'] = sql_result['user_id'] - session['USERNAME'] = sql_result['username'] - session['last_creation_time'] = 0 - session['vip'] = sql_result['vip'] - return redirect('/') - - -@main.route('/logout') -#@login_required -def logout(): - #logout_user() - session['user_id'] = -1 - session['USERNAME'] = None - session['login'] = False - session['last_creation_time'] = None - session['vip'] = None - return redirect('/login') - - -@main.route('/signup') -def signup(): - return render_template('signup.html') - - -@main.route('/signup', methods=['POST']) -def signup_post(): - username = request.form.get('username') - password = request.form.get('password') - confirm_password = request.form.get('confirm_password') - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute('select * from users where username=%s', (username,)) - sql_result = cur.fetchone() - if sql_result: # if a user is found, we want to redirect back to signup page so user can try again - cur.close() - conn.close() - flash('這個Email地址已經被使用', 'danger') - return redirect('/signup') - - if not (password == confirm_password): - cur.close() - conn.close() - flash('所輸入兩次密碼不同', 'danger') - return redirect('/signup') - - # create new user with the form data. Hash the password so plaintext version isn't saved. - cur.execute('insert into users (username, password) values (%s, %s)', (username, generate_password_hash(password))) - conn.commit() - cur.close() - conn.close() - - print('registered') - flash('已成功註冊', 'success') - - return redirect('/login') - - -@main.route('/forum') -def forum_index(): - if not (session.get('USERNAME') and session['USERNAME']): - flash('使用此功能必須先登入。', 'danger') - return redirect('/login') - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute("""select * from strategy - where competition not in (""" + confidential_competitions_placeholder + """) or author=%s - order by strategy_id desc;""", - confidential_competitions_list + (session['USERNAME'],)) - data = cur.fetchall() - cur.close() - conn.close() - - content_list = [] - for d in data: - content_list.append({ - "id": d['strategy_id'], - "time": d['create_date'], - "user_id": None, - "user_email": None, - "user_name": d['author'], - "comment": None, - "title": d['strategy_name'], - "video_id": None - }) - - return_data = { - "count": len(data), - "content": content_list - } - - return render_template('forum.html', forum_data=return_data) - - -@main.route('/post_page', methods=['GET']) -# @login_required -def post_page(): - if not (session.get('USERNAME') and session['USERNAME']): - flash('使用此功能必須先登入。', 'danger') - return redirect('/login') - post_id = int(request.values.get('post_id')) - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - - cur.execute('update strategy set click_count=click_count+1 where strategy_id=%s', (post_id,)) - conn.commit() - - cur.execute('select * from strategy where strategy_id=%s', (post_id,)) - strategy_content_list = cur.fetchone() - cur.execute('select * from assets_in_strategy where strategy_id=%s', (post_id,)) - asset_list = cur.fetchall() - cur.execute('select * from comment where strategy_id=%s', (post_id,)) - comment_list = cur.fetchall() - cur.close() - conn.close() - - print(asset_list) - - with open('latest_trading_data.txt') as all_data: - all_data_close = json.load(all_data) - - return_data = { - "strategy_content": strategy_content_list, - "asset_content": asset_list, - "comment_content": comment_list, - "comment_count": len(comment_list), - "asset_candidates": dict(asset_candidates + asset_candidates_tw), - "all_trading_data": all_data_close - } - - return render_template('post_page.html', data=return_data, strategy_id=str(post_id)) - -@main.route('/comment', methods=['POST']) -#@login_required -def post_comment_data(): - comment = request.form['comment'] - strategy_id = request.form['strategy_id'] - author = session['USERNAME'] - utc = datetime.utcnow() - utc = utc.replace(tzinfo=pytz.utc) - comment_date = datetime.strftime(utc.astimezone(pytz.timezone('Asia/Taipei')), '%Y/%m/%d %H:%M') - # comment_date = datetime.strftime(datetime.utcnow().astimezone(pytz.timezone('Asia/Taipei')), '%Y/%m/%d %H:%M') - # comment_date = datetime.strftime(datetime.utcnow().replace(tzinfo=pytz.timezone('Asia/Taipei')), '%Y/%m/%d %H:%M') - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - cur.execute('insert into comment (author, strategy_id, comment, date) values (%s, %s, %s, %s)', (author, strategy_id, comment, comment_date)) - conn.commit() - - cur.close() - conn.close() - return redirect('/post_page?post_id='+str(strategy_id)) - - -#@main.route('/profile') -#@login_required -#def profile(): -# return render_template('profile.html', name=current_user.name) - - -@main.route('/analysis_result') -#@login_required -def analysis_result(): - if not (session.get('USERNAME') and session['USERNAME']): - flash('使用此功能必須先登入。', 'danger') - return redirect('/login') - - sortby = request.values.get('sortby') - competition = request.values.get('competition') - tw = request.values.get('tw') - tw_digit = 1 if tw=='true' else 0 if tw=='false' else None - - conn = psycopg2.connect(database=POSTGRESQL_DATABASE, user=POSTGRESQL_USER) - cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) - if sortby == 'competition': - if competition in confidential_competitions_list: - cur.close() - conn.close() - flash('本競賽暫不開放查詢', 'danger') - return redirect('analysis_result?sortby=default&tw=' + tw +'&competition=none') - cur.execute("""select b.strategy_id, - a.author, - b.create_date, - b.return, - a.sharpe_ratio, - b.max_drawdown, - b.strategy_name, - b.volatility - from (select author, max(sharpe_ratio) as sharpe_ratio from strategy group by author) as a - join strategy as b on a.author=b.author and a.sharpe_ratio=b.sharpe_ratio - where b.competition=%s - order by a.sharpe_ratio desc;""", (competition,)) - #cur.execute("""select strategy_id, - # author, - # create_date, - # return, - # max(sharpe_ratio) as sharpe_ratio, - # max_drawdown, - # strategy_name, - # volatility - # from strategy - # where competition=%s - # group by author - # order by sharpe_ratio desc;""", (competition,)) - sql_results = cur.fetchall() - num_records_hidden = min(5, len(sql_results)) - if session['vip']==False: - for i in range(num_records_hidden): - for key in sql_results[i].keys(): - if key not in ['return', 'sharpe_ratio', 'max_drawdown', 'volatility']: - sql_results[i][key] = '*****' - elif sortby == 'default': - cur.execute("""select * from strategy - where tw=%s and (competition not in (""" + confidential_competitions_placeholder + """) or author=%s) - order by strategy_id desc limit 200;""", - (tw_digit,) + confidential_competitions_list + (session['USERNAME'],)) - sql_results = cur.fetchall() - elif sortby == 'myself': - cur.execute("""select * from strategy - where tw=%s and author=%s - order by strategy_id desc;""", - (tw_digit, session['USERNAME'])) - sql_results = cur.fetchall() - elif sortby == 'return': - cur.execute("""select * from strategy - where tw=%s and (competition not in (""" + confidential_competitions_placeholder + """) or author=%s) - order by return desc limit 1000;""", - (tw_digit,) + confidential_competitions_list + (session['USERNAME'],)) - sql_results = cur.fetchall() - # num_records_hidden = min(5, len(sql_results)) - # if session['vip']==False: - # for i in range(num_records_hidden): - # for key in sql_results[i].keys(): - # if key not in ['return', 'sharpe_ratio', 'max_drawdown', 'volatility']: - # sql_results[i][key] = '*****' - if session['vip']==False: - return_threshold = 1 - for record in sql_results: - if record['return'] > return_threshold: - for key in record.keys(): - if key not in ['return', 'sharpe_ratio', 'max_drawdown', 'volatility']: - record[key] = '*****' - else: - break - elif sortby == 'sharpe': - cur.execute("""select * from strategy - where tw=%s and (competition not in (""" + confidential_competitions_placeholder + """) or author=%s) and sharpe_ratio!='NaN' - order by sharpe_ratio desc limit 1000;""", - (tw_digit,) + confidential_competitions_list + (session['USERNAME'],)) - sql_results = cur.fetchall() - if session['vip']==False: - sharpe_threshold = 5 - for record in sql_results: - if record['sharpe_ratio'] > sharpe_threshold: - for key in record.keys(): - if key not in ['return', 'sharpe_ratio', 'max_drawdown', 'volatility']: - record[key] = '*****' - else: - break - elif sortby == 'vol': - cur.execute("""select * from strategy - where tw=%s and (competition not in (""" + confidential_competitions_placeholder + """) or author=%s) and volatility!=0 - order by volatility asc limit 1000;""", - (tw_digit,) + confidential_competitions_list + (session['USERNAME'],)) - sql_results = cur.fetchall() - if session['vip']==False: - vol_threshold = 0.1 - for record in sql_results: - if record['volatility'] < vol_threshold: - for key in record.keys(): - if key not in ['return', 'sharpe_ratio', 'max_drawdown', 'volatility']: - record[key] = '*****' - else: - break - elif sortby == 'mdd': - cur.execute("""select * from strategy - where tw=%s and (competition not in (""" + confidential_competitions_placeholder + """) or author=%s) and max_drawdown!=0 - order by max_drawdown asc limit 1000;""", - (tw_digit,) + confidential_competitions_list + (session['USERNAME'],)) - sql_results = cur.fetchall() - if session['vip']==False: - mdd_threshold = 0.15 - for record in sql_results: - if record['max_drawdown'] < mdd_threshold: - for key in record.keys(): - if key not in ['return', 'sharpe_ratio', 'max_drawdown', 'volatility']: - record[key] = '*****' - else: - break - cur.close() - conn.close() - return render_template('result.html', results=sql_results, tw=tw) - - -if __name__ == "__main__": - main.run(host='0.0.0.0', port=80) diff --git a/t.html b/t.html deleted file mode 100644 index b47f9c4..0000000 --- a/t.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - Serial Information - - - - - - - - - - -
-

Serial Information

- - -
- - - - -
- - - - - - - - - - - - - - - - - - - - - - -
Serial NumberDescription
001Serial 001 Information
002Serial 002 Information
003Serial 003 Information
-
- {{ item.title }} -
-
{{ item.title }}
-

{{ item.description }}

-
- -
-
- - - - - - - - - - - - diff --git a/templates/base.html b/templates/base.html index 5d7ddc7..0211195 100644 --- a/templates/base.html +++ b/templates/base.html @@ -54,7 +54,6 @@ ('/strategy_tw', 'strategy_tw', '台股建立策略', 'bi bi-piggy-bank-fill'), ('/custom', 'custom', '自訂數據建立策略', 'bi bi-database-fill-add'), ('/result', 'result', '分析結果排行', 'bi bi-graph-up-arrow'), - ('/result_tw', 'result_tw', '分析結果排行(台股)', 'bi bi-graph-up-arrow'), ('mailto:r10246002@ntu.edu.tw', 'error', '錯誤回報', 'bi bi-bug-fill') ] -%} {% set active_page = active_page|default('index') -%} diff --git a/templates/result.html b/templates/result.html index 393f6bb..5e1b979 100644 --- a/templates/result.html +++ b/templates/result.html @@ -25,7 +25,7 @@ body {
- +
diff --git a/templates/result_tw.html b/templates/result_tw.html deleted file mode 100644 index 4aa5b2a..0000000 --- a/templates/result_tw.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends 'base.html' %} -{% set active_page = 'result_tw' %} - - -{% block title %}Strategy Page{% endblock%} -{% block content %}Hello world - {{ active_page|e }} - -{% endblock %} diff --git a/templates/strategy.html b/templates/strategy.html deleted file mode 100644 index cf047de..0000000 --- a/templates/strategy.html +++ /dev/null @@ -1,164 +0,0 @@ -{% extends 'base.html' %} -{% set active_page = 'strategy_tw' %} - - -{% block title %}Strategy Page{% endblock%} -{% block style %} -.input-group{ - border: 1px solid #8E8E8E; - border-radius: 7px; -} -.input-group > span{ - bg-dark; - font-bold; -} -{% endblock style %} - -{% block content %} -
-
-
- ... -
-
投資組合建立步驟
-
    -
  1. 輸入投資組合名稱
  2. -
  3. 選擇所參加的課程或競賽
  4. -
  5. 選擇資產 (可使用搜索功能篩選)
  6. -
  7. 確認資產後按下 "確認資產", 查看資產價格動態圖表
  8. -
  9. 選擇訓練 / 回測數據比例與最佳化目標函數
  10. -
  11. 確認後按下 "建立投資組合", 查看回傳訊息
  12. -
-
-
-
- 投資組合名稱 - -
-
- 請選擇所參加的課程/競賽 - -
-
- 搜尋 - - 下方加入資產 -
-
- 請選擇資產 - - - -
-
-
-
- 已選擇的資產 -
-
- - -
-
-
-
- 請選擇訓練 / 回測數據比例 / 最佳化目標函數 - - -
-
    -
  1. - 2330.TW | 台積電 | 2000-01-05 ~ - - - -
  2. -
-
-
-
-
- - - -
-
- -{% endblock %} - - - - -{% block script %} - - -{% endblock script %} -