diff --git "a/\347\255\226\347\225\2451\357\274\232\346\212\200\346\234\257\346\214\207\346\240\207MACD \351\207\221\345\217\211+MA \345\244\232\345\244\264.py" "b/\347\255\226\347\225\2451\357\274\232\346\212\200\346\234\257\346\214\207\346\240\207MACD \351\207\221\345\217\211+MA \345\244\232\345\244\264.py" new file mode 100644 index 0000000..928c522 --- /dev/null +++ "b/\347\255\226\347\225\2451\357\274\232\346\212\200\346\234\257\346\214\207\346\240\207MACD \351\207\221\345\217\211+MA \345\244\232\345\244\264.py" @@ -0,0 +1,109 @@ +instruments =['000021.SZA','000034.SZA','000066.SZA','000158.SZA','000555.SZA','000606.SZA','000662.SZA','000938.SZA','000948.SZA','000606.SZA','300157.SZA','300164.SZA','300191.SZA','600121.SHA','600123.SHA','600157.SHA','600188.SHA','600193.SHA','600295.SHA','600339.SHA','300610.SZA','300637.SZA','300641.SZA','300655.SZA','300665.SZA','300690.SZA','300699.SZA','300716.SZA','300717.SZA','300721.SZA','000060.SZA','000426.SZA','000511.SZA','000603.SZA','000612.SZA','000630.SZA','000633.SZA','000657.SZA','000688.SZA','000693.SZA','300592.SZA','300621.SZA','300635.SZA','300649.SZA','300668.SZA','600039.SHA','600068.SHA','600133.SHA','600170.SHA','600209.SHA','603218.SHA','603320.SHA','603333.SHA','603396.SHA','603416.SHA','603488.SHA','603507.SHA','603577.SHA','603606.SHA','603488.SHA','300403.SZA','300475.SZA','600060.SHA','600336.SHA','600619.SHA','600690.SHA','600839.SHA','600854.SHA','600870.SHA','600983.SHA','600867.SHA','600896.SHA','600976.SHA','600993.SHA','600998.SHA','601607.SHA','603079.SHA','603108.SHA','603127.SHA','603139.SHA','002351.SZA','002369.SZA','002371.SZA','002388.SZA','002384.SZA','002402.SZA','002414.SZA','002463.SZA','002475.SZA','002484.SZA','002711.SZA','002769.SZA','002800.SZA','002889.SZA','300013.SZA','300240.SZA','300350.SZA','600004.SHA','600009.SHA','600026.SHA','601128.SHA','601166.SHA','601169.SHA','601229.SHA','601288.SHA','601398.SHA','601328.SHA','601818.SHA','601939.SHA','601988.SHA','600804.SHA','603042.SHA','603083.SHA','603118.SHA','603322.SHA','603421.SHA','603559.SHA','603602.SHA','603703.SHA','603803.SHA'] + +start_date = '20190103' +end_date = '20210122' + +import json +import talib +import numpy as np + + +def initialize(context): + # MACD 金叉MA 多头 指标设置DIF 短线=12, DIF 长线=26, DEA=9 + context.short_period = 12 + context.long_period = 26 + context.dea = 9 + + context.trading_day_count = 0 + + # MA 多头 MA 短线=5,MA 长线=20 + context.ma_short = 5 + context.ma_long = 20 + + # 资金 + context.cash = 10000 + + # 交易费用 + context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0003, min_cost=5)) + + +def is_all_nan(data): + for datum in data: + if str(datum) != 'nan': + return False + return True + + +# 计算MACD +def macd(context, data): + stock_set = set() + d = data.history(data.keys(), 'price', bar_count=34, frequency='1d') + for key in data.keys(): + s = np.asarray(d[key]) + if not is_all_nan(s): + macd, macdsignal, macdhist = talib.MACD(s, context.short_period, context.long_period, context.dea) + if macdhist[-1] > 0: + stock_set.add(key.symbol) + return stock_set + + +# 计算MA +def ma(context, data): + stock_set = set() + d_5 = data.history(data.keys(), 'price', bar_count=5, frequency='1d') + d_20 = data.history(data.keys(), 'price', bar_count=20, frequency='1d') + + for key in data.keys(): + s_5 = np.asarray(d_5[key]) + s_20 = np.asarray(d_20[key]) + if not is_all_nan(s_5) and not is_all_nan(s_20): + ma5 = talib.MA(s_5, timeperiod=5, matype=0) + ma20 = talib.MA(s_20, timeperiod=20, matype=0) + if ma5[-1] > ma20[-1]: + stock_set.add(key.symbol) + + return stock_set + + +def handle_data(context, data): + # 每20日交易一次 + if context.trading_day_count % 20 == 0: + + set_macd = macd(context, data) + set_ma = ma(context, data) + candidate_list = list(set_macd & set_ma) + max_stock_count = 10 + if len(candidate_list) > max_stock_count: + candidate_list = candidate_list[0:10] + + # 全部卖出 + for equity in context.portfolio.positions: + position = context.portfolio.positions[equity] + sid = position.sid + if data.can_trade(sid): + context.order_target_percent(sid, 0) + + cash = context.portfolio.cash + + # 买入 + for stock in candidate_list: + sid = context.symbol(stock) + if data.can_trade(sid): + price = data.current(sid, 'price') + context.order(sid, int(cash / price / 100 / len(candidate_list)) * 100) + + # 交易日+1 + context.trading_day_count = context.trading_day_count + 1 + + +m=M.trade.v2( + instruments=instruments, + start_date=start_date, + end_date=end_date, + initialize=initialize, + handle_data=handle_data, + order_price_field_buy='open', # 以开盘价买入 + order_price_field_sell='open', # 以开盘价卖出 + capital_base=100000, # 本金 + m_deps=np.random.randn() + ) \ No newline at end of file diff --git "a/\347\255\226\347\225\2452\357\274\232\346\212\200\346\234\257\346\214\207\346\240\207\350\207\252\345\256\232\344\271\211\347\255\226\347\225\245.py" "b/\347\255\226\347\225\2452\357\274\232\346\212\200\346\234\257\346\214\207\346\240\207\350\207\252\345\256\232\344\271\211\347\255\226\347\225\245.py" new file mode 100644 index 0000000..34b9abf --- /dev/null +++ "b/\347\255\226\347\225\2452\357\274\232\346\212\200\346\234\257\346\214\207\346\240\207\350\207\252\345\256\232\344\271\211\347\255\226\347\225\245.py" @@ -0,0 +1,135 @@ +instruments =['000021.SZA','000034.SZA','000066.SZA','000158.SZA','000555.SZA','000606.SZA','000662.SZA','000938.SZA','000948.SZA','000606.SZA','300157.SZA','300164.SZA','300191.SZA','600121.SHA','600123.SHA','600157.SHA','600188.SHA','600193.SHA','600295.SHA','600339.SHA','300610.SZA','300637.SZA','300641.SZA','300655.SZA','300665.SZA','300690.SZA','300699.SZA','300716.SZA','300717.SZA','300721.SZA','000060.SZA','000426.SZA','000511.SZA','000603.SZA','000612.SZA','000630.SZA','000633.SZA','000657.SZA','000688.SZA','000693.SZA','300592.SZA','300621.SZA','300635.SZA','300649.SZA','300668.SZA','600039.SHA','600068.SHA','600133.SHA','600170.SHA','600209.SHA','603218.SHA','603320.SHA','603333.SHA','603396.SHA','603416.SHA','603488.SHA','603507.SHA','603577.SHA','603606.SHA','603488.SHA','300403.SZA','300475.SZA','600060.SHA','600336.SHA','600619.SHA','600690.SHA','600839.SHA','600854.SHA','600870.SHA','600983.SHA','600867.SHA','600896.SHA','600976.SHA','600993.SHA','600998.SHA','601607.SHA','603079.SHA','603108.SHA','603127.SHA','603139.SHA','002351.SZA','002369.SZA','002371.SZA','002388.SZA','002384.SZA','002402.SZA','002414.SZA','002463.SZA','002475.SZA','002484.SZA','002711.SZA','002769.SZA','002800.SZA','002889.SZA','300013.SZA','300240.SZA','300350.SZA','600004.SHA','600009.SHA','600026.SHA','601128.SHA','601166.SHA','601169.SHA','601229.SHA','601288.SHA','601398.SHA','601328.SHA','601818.SHA','601939.SHA','601988.SHA','600804.SHA','603042.SHA','603083.SHA','603118.SHA','603322.SHA','603421.SHA','603559.SHA','603602.SHA','603703.SHA','603803.SHA'] + +start_date = '20190103' +end_date = '20210122' + +import json +import talib +import numpy as np + + +def initialize(context): + # MACD 金叉MA 多头 指标设置DIF 短线=12, DIF 长线=26, DEA=9 + context.short_period = 12 + context.long_period = 26 + context.dea = 9 + + context.trading_day_count = 0 + + # MA 多头 MA 短线=5,MA 长线=20 + context.ma_short = 5 + context.ma_long = 20 + + # 资金 + context.cash = 10000 + + # 交易费用 + context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0003, min_cost=5)) + + +def is_all_nan(data): + for datum in data: + if str(datum) != 'nan': + return False + return True + + +def min_cap(context, data): + market_cap_data = D.history_data(instruments, data.current_dt, data.current_dt, + fields=['market_cap', 'amount', 'suspended']) + # 根据是否停牌的字段确定每日选出来的股票 + daily_buy_stock = market_cap_data.groupby('date').apply(lambda df: df[(df['amount'] > 0) # 需要有成交量 + & (df['suspended'] == False) # 是否停牌 + ].sort_values('market_cap')[:10]) # + # context.logger.info(daily_buy_stock['instrument']) + return set(daily_buy_stock['instrument']) + + +# 计算MACD +def macd(context, data): + stock_set = set() + d = data.history(data.keys(), 'price', bar_count=34, frequency='1d') + for key in data.keys(): + s = np.asarray(d[key]) + if not is_all_nan(s): + macd, macdsignal, macdhist = talib.MACD(s, context.short_period, context.long_period, context.dea) + if macdhist[-1] > 0: + stock_set.add(key.symbol) + return stock_set + + +# 计算MA +def ma(context, data): + stock_set = set() + d_5 = data.history(data.keys(), 'price', bar_count=5, frequency='1d') + d_20 = data.history(data.keys(), 'price', bar_count=20, frequency='1d') + + for key in data.keys(): + s_5 = np.asarray(d_5[key]) + s_20 = np.asarray(d_20[key]) + if not is_all_nan(s_5) and not is_all_nan(s_20): + ma5 = talib.MA(s_5, timeperiod=5, matype=0) + ma20 = talib.MA(s_20, timeperiod=20, matype=0) + if ma5[-1] > ma20[-1]: + stock_set.add(key.symbol) + + return stock_set + + +def rebalance(context, data): + set_cap = min_cap(context, data) + # context.logger.info(set_cap) + set_macd = macd(context, data) + set_ma = ma(context, data) + candidate_list = list(set_cap & set_macd & set_ma) + max_stock_count = 10 + if len(candidate_list) > max_stock_count: + candidate_list = candidate_list[0:10] + + if len(candidate_list) > 0: + + # 当前持有的股票 + stock_hold_now = [equity.symbol for equity in context.portfolio.positions] + + # 无需卖出 + stock_not_to_sell = [i for i in stock_hold_now if i in candidate_list] + + # 需要卖出的股票 + stock_to_sell = [i for i in stock_hold_now if i not in stock_not_to_sell] + + # 卖出 + for stock in stock_to_sell: + if data.can_trade(context.symbol(stock)): + context.order_target_percent(context.symbol(stock), 0) + + # 等权重买入 + weight = 1 / len(candidate_list) + + # 买入 + for stock in candidate_list: + if data.can_trade(context.symbol(stock)): + context.order_target_percent(context.symbol(stock), weight) + + # 交易日+1 + context.trading_day_count = context.trading_day_count + 1 + + +def handle_data(context, data): + # 每10日交易一次 + if context.trading_day_count % 20 == 0: + rebalance(context, data) + + + + +m=M.trade.v2( + instruments=instruments, + start_date=start_date, + end_date=end_date, + initialize=initialize, + handle_data=handle_data, + order_price_field_buy='open', # 以开盘价买入 + order_price_field_sell='open', # 以开盘价卖出 + capital_base=100000, # 本金 + m_deps=np.random.randn() + ) \ No newline at end of file diff --git "a/\347\255\226\347\225\2453\357\274\232QP.py" "b/\347\255\226\347\225\2453\357\274\232QP.py" new file mode 100644 index 0000000..73b8f90 --- /dev/null +++ "b/\347\255\226\347\225\2453\357\274\232QP.py" @@ -0,0 +1,63 @@ +instruments =['000021.SZA','000034.SZA','000066.SZA','000158.SZA','000555.SZA','000606.SZA','000662.SZA','000938.SZA','000948.SZA','000606.SZA','300157.SZA','300164.SZA','300191.SZA','600121.SHA','600123.SHA','600157.SHA','600188.SHA','600193.SHA','600295.SHA','600339.SHA','300610.SZA','300637.SZA','300641.SZA','300655.SZA','300665.SZA','300690.SZA','300699.SZA','300716.SZA','300717.SZA','300721.SZA','000060.SZA','000426.SZA','000511.SZA','000603.SZA','000612.SZA','000630.SZA','000633.SZA','000657.SZA','000688.SZA','000693.SZA','300592.SZA','300621.SZA','300635.SZA','300649.SZA','300668.SZA','600039.SHA','600068.SHA','600133.SHA','600170.SHA','600209.SHA','603218.SHA','603320.SHA','603333.SHA','603396.SHA','603416.SHA','603488.SHA','603507.SHA','603577.SHA','603606.SHA','603488.SHA','300403.SZA','300475.SZA','600060.SHA','600336.SHA','600619.SHA','600690.SHA','600839.SHA','600854.SHA','600870.SHA','600983.SHA','600867.SHA','600896.SHA','600976.SHA','600993.SHA','600998.SHA','601607.SHA','603079.SHA','603108.SHA','603127.SHA','603139.SHA','002351.SZA','002369.SZA','002371.SZA','002388.SZA','002384.SZA','002402.SZA','002414.SZA','002463.SZA','002475.SZA','002484.SZA','002711.SZA','002769.SZA','002800.SZA','002889.SZA','300013.SZA','300240.SZA','300350.SZA','600004.SHA','600009.SHA','600026.SHA','601128.SHA','601166.SHA','601169.SHA','601229.SHA','601288.SHA','601398.SHA','601328.SHA','601818.SHA','601939.SHA','601988.SHA','600804.SHA','603042.SHA','603083.SHA','603118.SHA','603322.SHA','603421.SHA','603559.SHA','603602.SHA','603703.SHA','603803.SHA'] + +start_date = '20190103' +end_date = '20210122' + +import json +import talib +import numpy as np +import cvxopt as opt +from cvxopt import blas, solvers + +solvers.options['show_progress'] = False + +def initialize(context): + + context.set_commission(PerOrder(buy_cost=0.003, sell_cost=0.003, min_cost=5)) + + +def optimal_portfolio(returns): + returns = np.asmatrix(returns) + n = len(returns) + + # 转化为cvxopt matrices + # Σ: 这是收益的协方差矩阵,代表着股票之间的关系 + S = opt.matrix(np.cov(returns)) + # μ = (μ1, ..., μn):这是通过历史数据计算出来的每只股票的期望收益。 + pbar = opt.matrix(np.mean(returns, axis=1)) + + # 约束条件 + G = -opt.matrix(np.eye(n)) + h = opt.matrix(0.0, (n, 1)) + A = opt.matrix(1.0, (1, n)) + b = opt.matrix(1.0) + + # 使用凸优化计算有效前沿 + # 计算最优组合 + wt = solvers.qp(opt.matrix(0.1 * S), -pbar, G, h, A, b)['x'] + return np.asarray(wt) + + +def handle_data(context, data): + if context.trading_day_index % 20 == 0: + + prices = data.history(data.keys(), fields='price', bar_count=6, frequency='1d').dropna( + axis=1).pct_change().dropna(axis=0) + + if not prices.empty: + weights = optimal_portfolio(prices.T) + for stock, weight in zip(prices.columns, weights): + if data.can_trade(stock): + context.order_target_percent(stock, weight[0]) + +m=M.trade.v2( + instruments=instruments, + start_date=start_date, + end_date=end_date, + initialize=initialize, + handle_data=handle_data, + order_price_field_buy='open', # 以开盘价买入 + order_price_field_sell='open', # 以开盘价卖出 + capital_base=100000, # 本金 + m_deps=np.random.randn() + ) \ No newline at end of file diff --git "a/\347\255\226\347\225\2454\357\274\232QP + \345\244\232\346\240\267\346\200\247.py" "b/\347\255\226\347\225\2454\357\274\232QP + \345\244\232\346\240\267\346\200\247.py" new file mode 100644 index 0000000..5fc0ce7 --- /dev/null +++ "b/\347\255\226\347\225\2454\357\274\232QP + \345\244\232\346\240\267\346\200\247.py" @@ -0,0 +1,92 @@ + + + +start_date = '20190103' +end_date = '20210122' + +import pandas as pd +import json +import talib +import numpy as np +import cvxopt as opt +from cvxopt import blas, solvers + +solvers.options['show_progress'] = False + +# 股票 +df = pd.read_csv('stock_list.csv',header=None) +instruments = df[0].to_list() + +# 每个行业下股票数量 +industries = df[1].to_list() +industries_cnt = [industries.count(i) for i in np.unique(industries)] + + +def initialize(context): + # 设置手续费 + context.set_commission(PerOrder(buy_cost=0.003, sell_cost=0.003, min_cost=5)) + + context.rebalance_period = 20 + context.observation = 5 + context.max_weight_per_stock = 0.1 + context.max_weight_per_industry = 0.3 + + +def optimal_portfolio(context, returns): + returns = np.asmatrix(returns) + n = len(returns) + + # 转化为cvxopt matrices + S = opt.matrix(np.cov(returns)) + pbar = opt.matrix(np.mean(returns, axis=1)) + + # 初始约束条件 + G1 = -opt.matrix(np.eye(n)) + h1 = opt.matrix(0.0, (n, 1)) + # 每只股票权重限制 + G2 = opt.matrix(np.eye(n)) + h2 = opt.matrix(context.max_weight_per_stock, (n, 1)) + # 行业限制 + G3 = np.zeros((len(industries_cnt), n)) + start = 0 + end = 0 + for i in range(len(industries_cnt)): + end += industries_cnt[i] + G3[i, start:end] = 1 + start = end + G3 = opt.matrix(G3) + h3 = opt.matrix(context.max_weight_per_industry, (len(industries_cnt), 1)) + G = opt.matrix(np.concatenate([G1, G2, G3])) + h = opt.matrix(np.concatenate([h1, h2, h3])) + A = opt.matrix(1.0, (1, n)) + b = opt.matrix(1.0) + + # 使用凸优化计算有效前沿 + # 计算最优组合 + wt = solvers.qp(opt.matrix(0.1 * S), -pbar, G, h, A, b)['x'] + return np.asarray(wt) + + +def handle_data(context, data): + if context.trading_day_index % 20 == 0: + + prices = data.history(data.keys(), fields='price', bar_count=6, frequency='1d').dropna( + axis=1).pct_change().dropna(axis=0) + + if not prices.empty: + weights = optimal_portfolio(context, prices.T) + for stock, weight in zip(prices.columns, weights): + if data.can_trade(stock): + context.order_target_percent(stock, weight[0]) + +m=M.trade.v2( + instruments=instruments, + start_date=start_date, + end_date=end_date, + initialize=initialize, + handle_data=handle_data, + order_price_field_buy='open', # 以开盘价买入 + order_price_field_sell='open', # 以开盘价卖出 + capital_base=100000, # 本金 + m_deps=np.random.randn() + ) \ No newline at end of file diff --git "a/\347\255\226\347\225\2457\357\274\232QP + \350\207\252\345\256\232\344\271\211.py" "b/\347\255\226\347\225\2457\357\274\232QP + \350\207\252\345\256\232\344\271\211.py" new file mode 100644 index 0000000..896cb85 --- /dev/null +++ "b/\347\255\226\347\225\2457\357\274\232QP + \350\207\252\345\256\232\344\271\211.py" @@ -0,0 +1,137 @@ + +start_date = '20190103' +end_date = '20210122' + +import pandas as pd +import json +import talib +import numpy as np +import cvxopt as opt +from cvxopt import blas, solvers + +solvers.options['show_progress'] = False + +# 股票 +df = pd.read_csv('stock_list.csv',header=None) +instruments = df[0].to_list() + +# 每个行业下股票数量 +industries = df[1].to_list() +industries_cnt = [industries.count(i) for i in np.unique(industries)] + + +def initialize(context): + # 设置手续费 + context.set_commission(PerOrder(buy_cost=0.003, sell_cost=0.003, min_cost=5)) + + context.rebalance_period = 20 + context.observation = 5 + context.max_weight_per_stock = 0.1 + context.max_weight_per_industry = 0.3 + + +def optimal_portfolio(context, returns): + returns = np.asmatrix(returns) + n = len(returns) + + # 转化为cvxopt matrices + S = opt.matrix(np.cov(returns)) + pbar = opt.matrix(np.mean(returns, axis=1)) + + # 初始约束条件 + G1 = -opt.matrix(np.eye(n)) # opt默认是求最大值,因此要求最小化问题,还得乘以一个负号 + h1 = opt.matrix(0.0, (n, 1)) + # 每只股票权重限制 + G2 = opt.matrix(np.eye(n)) + h2 = opt.matrix(context.max_weight_per_stock, (n, 1)) + # 行业限制 + G3 = np.zeros((len(industries_cnt), n)) + start = 0 + end = 0 + for i in range(len(industries_cnt)): + end += industries_cnt[i] + G3[i, start:end] = 1 + start = end + G3 = opt.matrix(G3) + h3 = opt.matrix(context.max_weight_per_industry, (len(industries_cnt), 1)) + G = opt.matrix(np.concatenate([G1, G2, G3])) + h = opt.matrix(np.concatenate([h1, h2, h3])) + A = opt.matrix(1.0, (1, n)) + b = opt.matrix(1.0) + + # 使用凸优化计算有效前沿 + # 计算最优组合 + wt = solvers.qp(opt.matrix(0.1 * S), -pbar, G, h, A, b)['x'] + return np.asarray(wt) + + +def is_all_nan(data): + for datum in data: + if str(datum) != 'nan': + return False + return True + + +def min_cap(context, data): + market_cap_data = D.history_data(instruments, data.current_dt, data.current_dt, + fields=['market_cap', 'amount', 'suspended']) + # 根据是否停牌的字段确定每日选出来的股票 + daily_buy_stock = market_cap_data.groupby('date').apply(lambda df: df[(df['amount'] > 0) # 需要有成交量 + & (df['suspended'] == False) # 是否停牌 + ].sort_values('market_cap')[:30]) # + # context.logger.info(daily_buy_stock['instrument']) + return set(daily_buy_stock['instrument']) + + +# 计算MA +def ma(context, data): + stock_set = set() + d_5 = data.history(data.keys(), 'price', bar_count=5, frequency='1d') + d_20 = data.history(data.keys(), 'price', bar_count=20, frequency='1d') + + for key in data.keys(): + s_5 = np.asarray(d_5[key]) + s_20 = np.asarray(d_20[key]) + if not is_all_nan(s_5) and not is_all_nan(s_20): + ma5 = talib.MA(s_5, timeperiod=5, matype=0) + ma20 = talib.MA(s_20, timeperiod=20, matype=0) + if ma5[-1] > ma20[-1]: + stock_set.add(key.symbol) + + return stock_set + + +def handle_data(context, data): + if context.trading_day_index % 20 == 0: + + set_cap = min_cap(context, data) + set_ma = ma(context, data) + + candidate_list = list(set_cap & set_ma) + + candidate = [] + + for stock in candidate_list: + candidate.append(context.symbol(stock)) + + if len(candidate) > 1: + prices = data.history(candidate, fields='price', bar_count=6, frequency='1d').dropna( + axis=1).pct_change().dropna(axis=0) + + if not prices.empty: + weights = optimal_portfolio(context, prices.T) + for stock, weight in zip(prices.columns, weights): + if data.can_trade(stock): + context.order_target_percent(stock, weight[0]) + +m=M.trade.v2( + instruments=instruments, + start_date=start_date, + end_date=end_date, + initialize=initialize, + handle_data=handle_data, + order_price_field_buy='open', # 以开盘价买入 + order_price_field_sell='open', # 以开盘价卖出 + capital_base=100000, # 本金 + m_deps=np.random.randn() + ) \ No newline at end of file