├── README.md
├── joinquant_rsrs因子_年均18%收益.py
├── joinquant_网格交易_v1.py
├── joinquant_计算macd值与同花顺不一致原因探索.py
├── okx_contract_swap_demo.py
├── okx_spot_inst_demo.py
├── qmt_macd策略.py
└── 微信群.jpg
/README.md:
--------------------------------------------------------------------------------
1 | # Quant Strategy 量化策略
2 | qmt、ptrade、okx、bnb、joinquant聚宽
3 | [点这里](README.md) 查看格式更好
4 |
5 | 这是一个量化代码合集,目前是以qmt、okx、聚宽为主,逐步完善
6 | ## 关于作者
7 | | 平台 | 链接 | 说明 |
8 | |:-------|:-------:|-------:|
9 | | 微信 | yiyou888wx | 备注GitHub |
10 | | 微信群 | 请往下翻 | 技术交流 |
11 | | QQ群 | 983459113 | 资料下载 |
12 | | csdn博客 | [点击跳转](https://blog.csdn.net/2401_82851462) | 发布最及时 |
13 | | joinquant聚宽 | [点击跳转](https://www.joinquant.com/view/community/detail/2e31e2d643c391e9eeed79e4d107c0fd) | 可复制回测 |
14 | | 小红书 | 搜"芒果量化" | 图文解说 |
15 | | X/telegram | TraderMaga59800 | Foreign users |
16 |
17 | (可开户、代写)量化优势:对抗人性、不用盯盘
18 | 麻烦点个小星星支持一下哦~
19 | Please give a star to support it.
20 |
21 | 加微信群,更多技术畅聊!(5.7有效)
22 |
23 |
24 |
25 | ## 内容介绍
26 | | 平台 | 说明 | 文件 | 外部链接 |
27 | |:-------|:-------:|-------:|-------:|
28 | | **聚宽** | 年均18%,44行代码 | [joinquant_rsrs因子_年均18%收益.py](joinquant_rsrs因子_年均18%收益.py) | [点击跳转](https://www.joinquant.com/view/community/detail/4b45a0d76897c3463b394a1ef554041a) |
29 | | **聚宽** | 网格交易,适合震荡 | [joinquant_网格交易_v1.py](joinquant_网格交易_v1.py) | [点击跳转](https://www.joinquant.com/view/community/detail/fc1595a15fabbfea7bd85d033ba3dbbe) |
30 | | **聚宽** | macd不一致研究 | [joinquant_计算macd值与同花顺不一致原因探索.py](joinquant_计算macd值与同花顺不一致原因探索.py) | [点击跳转](https://www.joinquant.com/view/community/detail/6d7405065eaabd64d156ca52b6ed548b) |
31 | | ---- | -------- | -------- | -------- |
32 | | **qmt** | macd策略,实时交易 | [qmt_macd策略.py](qmt_macd策略.py) | [点击跳转](https://blog.csdn.net/2401_82851462/article/details/146592641) |
33 | | ---- | -------- | -------- | -------- |
34 | | **okx** | okx现货交易代码 | [okx_spot_inst_demo.py](okx_spot_inst_demo.py) | [点击跳转](https://blog.csdn.net/2401_82851462/article/details/146811185) |
35 | | okx | okx合约交易代码 | [okx_contract_swap_demo.py](okx_contract_swap_demo.py) | [点击跳转](https://blog.csdn.net/2401_82851462/article/details/146639685) |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/joinquant_rsrs因子_年均18%收益.py:
--------------------------------------------------------------------------------
1 | # 导入函数库
2 | from jqdata import *
3 | import pandas as pd
4 | import numpy as np
5 | import statsmodels.api as sm
6 |
7 | def initialize(context):
8 | set_benchmark('000300.XSHG')
9 | set_option('use_real_price', True)
10 | set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
11 | g.security = '000300.XSHG'
12 | g.buy_beta, g.sell_beta = 0.7, -0.7
13 | g.is_first, g.beta_list, g.r2_list = True, [], []
14 | run_daily(market_open, time='open', reference_security='000300.XSHG')
15 |
16 | def calculate_rsrs(end_date='', n=18, m=1100):
17 | # n: 一阶拟合样本数,m:求均值方差样本数; 采用普通最小二乘法拟合,前面算过的就不重复计算了
18 | if g.is_first:
19 | df = get_price(g.security, end_date=end_date, count=m+n, frequency='daily', fields=['high','low'])
20 | else:
21 | df = get_price(g.security, end_date=end_date, count=n, frequency='daily', fields=['high','low'])
22 | for i in range(len(df))[(-m if g.is_first else -1):]:
23 | x = sm.add_constant(df['low'][i-n+1:i+1])
24 | y = df['high'][i-n+1:i+1]
25 | model = sm.OLS(y, x).fit()
26 | beta = model.params[1]
27 | r2 = model.rsquared
28 | g.beta_list.append(beta)
29 | g.r2_list.append(r2)
30 | section = g.beta_list[-m:]
31 | mu = np.mean(section)
32 | sigma = np.std(section)
33 | z_score = (section[-1] - mu)/sigma
34 | z_score_right = z_score * beta * r2
35 | g.is_first = False
36 | return z_score_right
37 |
38 | def market_open(context):
39 | cash = context.portfolio.available_cash
40 | z_score_right = calculate_rsrs(context.previous_date)
41 | if z_score_right>g.buy_beta and cash>0:
42 | order_value(g.security, cash)
43 | elif z_score_right 0:
44 | order_target(g.security, 0)
--------------------------------------------------------------------------------
/joinquant_网格交易_v1.py:
--------------------------------------------------------------------------------
1 | # 导入函数库
2 | from jqdata import *
3 |
4 | # 初始化函数,设定基准等等
5 | def initialize(context):
6 | # 设定沪深300作为基准
7 | set_benchmark('000300.XSHG')
8 | # 开启动态复权模式(真实价格)
9 | set_option('use_real_price', True)
10 | # 输出内容到日志 log.info()
11 | log.info('初始函数开始运行且全局只运行一次')
12 | g.security = '000300.XSHG'
13 |
14 | # 设置网格参数
15 | g.grid_interval = 0.03 # 网格间距:3%
16 | g.grid_num = 5 # 网格数量:中间上下各5层
17 | g.base_price = None # 后续初始化
18 | g.position_ratio = 0.2 # 每格仓位变动比例
19 | # 是否已初始化网格
20 | g.inited = False
21 |
22 | ### 股票相关设定 ###
23 | # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
24 | set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
25 | run_daily(market_open, time='open', reference_security='000300.XSHG')
26 |
27 |
28 | ## 开盘时运行函数
29 | def market_open(context):
30 | price = get_current_data()[g.security].last_price
31 |
32 | # 初始化网格价格和初始持仓
33 | if not g.inited:
34 | g.base_price = price
35 | g.buy_grid = [g.base_price * (1 - g.grid_interval * i) for i in range(1, g.grid_num + 1)]
36 | g.sell_grid = [g.base_price * (1 + g.grid_interval * i) for i in range(1, g.grid_num + 1)]
37 | g.init_cash = context.portfolio.available_cash
38 | g.position_value_per_grid = g.init_cash * g.position_ratio
39 | log.info(f"初始化完成,当前价格:{price}")
40 | g.inited = True
41 | return
42 |
43 | current_position = context.portfolio.positions[g.security].value
44 | available_cash = context.portfolio.available_cash
45 |
46 | # 买入逻辑:当前价格低于某个买入网格且有资金
47 | for grid_price in g.buy_grid:
48 | if price <= grid_price and available_cash >= g.position_value_per_grid:
49 | amount = g.position_value_per_grid // price
50 | order(g.security, amount)
51 | log.info(f"低价买入:价格 {price:.2f} <= 网格 {grid_price:.2f}, 买入 {amount} 股")
52 | break # 每次只触发一格操作
53 |
54 | # 卖出逻辑:当前价格高于某个卖出网格且有仓位
55 | for grid_price in g.sell_grid:
56 | if price >= grid_price and current_position > 0:
57 | amount = g.position_value_per_grid // price
58 | hold_amount = context.portfolio.positions[g.security].total_amount
59 | order(g.security, -min(amount, hold_amount))
60 | log.info(f"高价卖出:价格 {price:.2f} >= 网格 {grid_price:.2f}, 卖出 {amount} 股")
61 | break # 每次只触发一格操作
62 |
63 |
--------------------------------------------------------------------------------
/joinquant_计算macd值与同花顺不一致原因探索.py:
--------------------------------------------------------------------------------
1 |
2 | # 这里仅为源代码展示,若复制需要从以下url进入
3 | # https://www.joinquant.com/view/community/detail/6d7405065eaabd64d156ca52b6ed548b
4 |
5 | # 一般人用talib来计算macd
6 | import talib
7 |
8 | class G:pass
9 | g = G()
10 |
11 | g.security = '000333.XSHE'
12 | df = get_price(g.security, end_date='2025-05-21', count=50, frequency='daily', fields=['close'])
13 | closes = df['close'].values
14 | print(f'closes:{closes}')
15 |
16 | dif, dea, macd = talib.MACD(closes, 12, 26, 9)
17 | print('DIF:', dif[-10:])
18 | print('DEA:', dea[-10:])
19 | print('MACD:', macd[-10:])
20 |
21 |
22 |
23 |
24 | # 研究差异(原创)
25 | '''
26 | 我们可以根据以下几点,来判断:
27 |
28 | a.数据是否对上
29 | closes收盘价和通达信上面显示的收盘价是否一致
30 |
31 | b.参数是否相同
32 | macd需要设置3个参数,要保证和通达信参数一致。比如这里均为12, 26, 9
33 |
34 | c.用talib计算出来的macd值需要乘以2
35 | 也就是 (dif - dea) * 2,否则永远对不上
36 |
37 | d.数据量要稍大一点【核心关键】
38 | 由于EMA初始化方式不同,talib和通达信在初期几天(尤其是前 30 天左右),MACD 指标差异明显,随着数据长度增长会逐渐收敛。
39 | 所以,我们可以设置数量设置大一点,比如为200
40 | '''
41 |
42 |
43 |
44 | # 改进之后
45 | df = get_price(g.security, end_date='2025-05-21', count=200, frequency='daily', fields=['close'])
46 | closes = df['close'].values
47 | dif, dea, macd = talib.MACD(closes, 12, 26, 9)
48 | # 通达信的 MACD 是 (dif - dea) * 2
49 | macd_tdx = (dif - dea) * 2
50 | # 最后对比末尾部分值
51 | print(dif[-10:])
52 | print(dea[-10:])
53 | print(macd_tdx[-10:])
54 |
55 | # 到此,结果完全一致,对上了!
56 |
57 |
58 |
59 |
60 | # 手动实现macd(不依赖talib库)也能对上
61 | import numpy as np
62 |
63 | def ema_tdx(data, period):
64 | """通达信风格的EMA,初始值为第一个价格"""
65 | ema = np.zeros_like(data)
66 | alpha = 2 / (period + 1)
67 | ema[0] = data[0]
68 | for i in range(1, len(data)):
69 | ema[i] = alpha * data[i] + (1 - alpha) * ema[i - 1]
70 | return ema
71 |
72 | def macd_tdx(close, short=12, long=26, mid=9):
73 | """通达信风格的MACD计算"""
74 | ema_short = ema_tdx(close, short)
75 | ema_long = ema_tdx(close, long)
76 | dif = ema_short - ema_long
77 | dea = ema_tdx(dif, mid)
78 | macd = 2 * (dif - dea)
79 | return dif, dea, macd
80 |
81 | # 使用通达信风格计算 MACD
82 | dif, dea, macd = macd_tdx(closes)
83 |
84 | # 打印最近几天的结果
85 | print('DIF:', dif[-10:])
86 | print('DEA:', dea[-10:])
87 | print('MACD:', macd[-10:])
88 |
--------------------------------------------------------------------------------
/okx_contract_swap_demo.py:
--------------------------------------------------------------------------------
1 | import time
2 | import okx.Trade as Trade
3 | import okx.Account as Account
4 | import okx.MarketData as MarketData
5 |
6 | # okx合约开仓平仓操作
7 | # OKX contract opening and closing operations
8 | # 作者威xin(可代写): yiyou888wx
9 | # X / telegram: TraderMaga59800
10 |
11 | # 注意主账号和子账号是分开的,模拟交易也是分开的
12 | # API 初始化 #API initialization
13 | apikey = "YOUR_API_KEY"
14 | secretkey = "YOUR_SECRET_KEY"
15 | passphrase = "YOUR_PASSPHRASE"
16 |
17 | ### ---------------------------------------------------------
18 |
19 | # 获取合约行情
20 | # Obtain contract market information
21 | # 实盘:0 , 模拟盘:1
22 | #Real: 0, simulation: 1
23 | flag = '1'
24 | marketDataAPI = MarketData.MarketAPI(flag=flag)
25 | result = marketDataAPI.get_ticker(instId='BTC-USDT-SWAP')
26 | print('获取合约行情(BTC-USDT-SWAP):')
27 | print(result)
28 | print()
29 |
30 | # 查看账户余额
31 | # View account balance
32 | accountAPI = Account.AccountAPI(apikey, secretkey, passphrase, False, flag)
33 | result = accountAPI.get_account_balance()
34 | print('查看账户余额:')
35 | print(result)
36 | print()
37 |
38 | # 获取用于购买BTC-USDT-SWAP最大可用USDT数量
39 | # Obtain the maximum available USDT quantity for purchasing BTC-USDT-SWAP
40 | result = accountAPI.get_max_avail_size(
41 | instId="BTC-USDT-SWAP",
42 | tdMode="isolated"
43 | )
44 | print('获取用于购买BTC-USDT-SWAP最大可用USDT数量:')
45 | print(result)
46 | print()
47 |
48 | # 查看持仓信息
49 | # View position information
50 | result = accountAPI.get_positions()
51 | print('查看持仓信息:')
52 | print(result)
53 | print()
54 |
55 | ### ---------------------------------------------------------
56 |
57 | # 查看账户配置(交易模式)
58 | # GET /api/v5/account/config
59 | result = accountAPI.get_account_config()
60 | print('查看账户配置:')
61 | print(result)
62 | print()
63 | # 账户模式 acctLv (Account mode)
64 | # 1:现货模式 Spot mode
65 | # 2:现货和合约模式 Spot and contract models
66 | # 持仓方式 posMode (Position holding method)
67 | # long_short_mode:开平仓模式 可以同时持有多头(买入)和空头(卖出)头寸; The opening and closing mode allows for holding both long (buy) and short (sell) positions simultaneously
68 | # net_mode:买卖模式 基于净头寸; Buy and sell mode based on net position
69 |
70 | # 设置账户模式(交易模式) #Set account mode (trading mode)
71 | # POST /api/v5/account/set-account-level
72 | # 这个比较麻烦,官方代码没有实现,我自己(yiyou888wx)实现如下:
73 | #This is quite troublesome as the official code has not been implemented. So I implement it as follows:
74 | Set_Account_Level = "/api/v5/account/set-account-level"
75 | class YiyouAPI(Account.AccountAPI):
76 | def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1',
77 | domain='https://www.okx.com', debug=False, proxy=None):
78 | super().__init__(api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy)
79 | def set_account_level(self, acctLv="1"):
80 | params = {"acctLv": str(acctLv)}
81 | return self._request_with_params("POST", Set_Account_Level, params)
82 |
83 | yiyouAPI = YiyouAPI(apikey, secretkey, passphrase, False, flag)
84 | result = yiyouAPI.set_account_level(acctLv="2")
85 | print('设置账户模式,为现货和合约模式:')
86 | print(result)
87 | print()
88 | result = accountAPI.get_account_config()
89 | print('查看账户配置:')
90 | print(result)
91 | print()
92 |
93 |
94 | # 获取杠杆倍数
95 | # Obtain leverage ratio
96 | result = accountAPI.get_leverage(
97 | instId="BTC-USDT-SWAP",
98 | # 保证金模式: 逐仓 #Margin mode: position by position
99 | mgnMode="isolated"
100 | )
101 | print('获取杠杆倍数:')
102 | print(result)
103 | print()
104 |
105 | # 设置杠杆倍数
106 | # Set leverage ratio
107 | result = accountAPI.set_leverage(
108 | instId="BTC-USDT-SWAP",
109 | lever="3",
110 | mgnMode="isolated",
111 | posSide="short"
112 | )
113 | print('设置做空杠杆倍数为3:')
114 | print(result)
115 | print()
116 | result = accountAPI.set_leverage(
117 | instId="BTC-USDT-SWAP",
118 | lever="4",
119 | mgnMode="isolated",
120 | posSide="long"
121 | )
122 | print('设置做多杠杆倍数为4:')
123 | print(result)
124 | print()
125 |
126 | # 获取杠杆倍数
127 | # Obtain leverage ratio
128 | result = accountAPI.get_leverage(
129 | instId="BTC-USDT-SWAP",
130 | mgnMode="isolated"
131 | )
132 | print('修改后,获取杠杆倍数:')
133 | print(result)
134 | print()
135 |
136 | ### ---------------------------------------------------------
137 |
138 |
139 | tradeAPI = Trade.TradeAPI(apikey, secretkey, passphrase, False, flag)
140 | # 4倍杠杆做多 (前面设置过)
141 | # Long with 4x leverage (previously set)
142 | result = tradeAPI.place_order(
143 | instId='BTC-USDT-SWAP',
144 | tdMode='isolated', # 逐仓模式 #Warehouse by warehouse mode
145 | # 注意clOrdId不能用下划线 #Note that clOrdId cannot be underlined
146 | clOrdId='mylong01',
147 | side='buy',
148 | posSide="long",
149 | ordType='market',
150 | sz="10" #单位是一张, 即0.01 BTC #The unit is 0.01 BTC
151 | )
152 | print('4倍杠杆做多:')
153 | print(result)
154 | print()
155 | # 碰到的报错:
156 | # 51000 Parameter clOrdId error 参数错误
157 | # 51010 当前账户模式不支持此操作
158 | # 51169 下单失败,当前合约无持仓,请先取消只减仓设置,再尝试下单
159 | # Order failed. You don't have any positions in this contract that can be closed.
160 | # 51008 可用余额不足 Order failed. Insufficient USDT balance in account.
161 |
162 | time.sleep(60)
163 | # 4倍杠杆做多,减仓
164 | # Long with 4x leverage, reduce position
165 | result = tradeAPI.place_order(
166 | instId='BTC-USDT-SWAP',
167 | tdMode='isolated',
168 | clOrdId='mylong02',
169 | side='sell',
170 | posSide="long",
171 | ordType='market',
172 | sz="3"
173 | )
174 | print('4倍杠杆做多,减仓:')
175 | print(result)
176 | print()
177 |
178 | time.sleep(60)
179 | # 市价全平
180 | # The market price is completely flat
181 | result = tradeAPI.close_positions(
182 | instId="BTC-USDT-SWAP",
183 | mgnMode="isolated",
184 | posSide="long"
185 | )
186 | print('4倍杠杆做多,市价全平:')
187 | print(result)
188 | print()
189 |
190 | time.sleep(60)
191 | # 3倍杠杆做空(前面设置过)
192 | # 3x leverage short selling (previously set)
193 | result = tradeAPI.place_order(
194 | instId='BTC-USDT-SWAP',
195 | tdMode='isolated', # 逐仓模式 #Warehouse by warehouse mode
196 | side='sell',
197 | posSide="short",
198 | ordType='market',
199 | sz="8"
200 | )
201 | print('3倍杠杆做空:')
202 | print(result)
203 | print()
204 |
205 | time.sleep(60)
206 | # 3倍杠杆做空减仓
207 | # 3x leverage short selling and reducing positions
208 | result = tradeAPI.place_order(
209 | instId='BTC-USDT-SWAP',
210 | tdMode='isolated',
211 | side='buy',
212 | posSide="short",
213 | ordType='market',
214 | sz="8"
215 | )
216 | print('3倍杠杆做空,减仓:')
217 | print(result)
218 | print('finish')
219 |
--------------------------------------------------------------------------------
/okx_spot_inst_demo.py:
--------------------------------------------------------------------------------
1 | import time
2 | import okx.Trade as Trade
3 | import okx.Account as Account
4 | import okx.MarketData as MarketData
5 |
6 | # okx现货买卖操作
7 | # OKX spot trading operation
8 | # 作者威xin(可代写): yiyou888wx
9 | # X / telegram: TraderMaga59800
10 |
11 | # 注意主账号和子账号是分开的,模拟交易也是分开的
12 | #Note that the main account and sub account are separate, and the simulated trading is also separate
13 | # API 初始化 #API initialization
14 | apikey = "YOUR_API_KEY"
15 | secretkey = "YOUR_SECRET_KEY"
16 | passphrase = "YOUR_PASSPHRASE"
17 | # from my_key import * # 可忽略此行 #This line can be ignored
18 |
19 | # 获取现货行情
20 | # Obtain contract market information
21 | # 实盘:0 , 模拟盘:1
22 | #Real: 0, simulation: 1
23 | flag = '1'
24 | marketDataAPI = MarketData.MarketAPI(flag=flag)
25 | result = marketDataAPI.get_ticker(instId='BTC-USDT')
26 | print('获取现货行情(BTC-USDT):')
27 | print(result)
28 | print()
29 |
30 | # 获取指数K线数据
31 | # Obtain index K-line data
32 | # 注意:不要使用"获取指数历史K线数据"接口,否则获取不到当前数据
33 | #Attention: Do not use the "Get Index Historical K-Line Data" interface, otherwise the current data cannot be obtained
34 | result = marketDataAPI.get_index_candlesticks(
35 | instId="BTC-USDT",
36 | limit=10
37 | )
38 | # ['ts', 'o', 'h', 'l', 'c', 'confirm']
39 | print('获取指数K线数据(BTC-USDT):')
40 | print(result)
41 | print()
42 |
43 | # 查看账户余额
44 | # View account balance
45 | accountAPI = Account.AccountAPI(apikey, secretkey, passphrase, False, flag)
46 | result = accountAPI.get_account_balance()
47 | print('查看账户余额:')
48 | print(result)
49 | print()
50 |
51 | # 买入现货 buy spot
52 | tradeAPI = Trade.TradeAPI(apikey, secretkey, passphrase, False, flag)
53 | result = tradeAPI.place_order(
54 | instId='BTC-USDT',
55 | tdMode='cash',
56 | side='buy',
57 | ordType='market',
58 | sz="9000" # 单位是USDT #The unit is USDT
59 | )
60 | print('买入BTC:')
61 | print(result)
62 | print()
63 |
64 | # 卖出现货 sell spot
65 | time.sleep(60)
66 | result = tradeAPI.place_order(
67 | instId='BTC-USDT',
68 | tdMode='cash',
69 | side='sell',
70 | ordType='market',
71 | sz="0.1" # 单位是BTC #The unit is BTC
72 | )
73 | print('卖出BTC:')
74 | print(result)
75 | print()
76 |
--------------------------------------------------------------------------------
/qmt_macd策略.py:
--------------------------------------------------------------------------------
1 | #encoding:gbk
2 | import talib
3 | import datetime
4 | import numpy as np
5 |
6 | # 《macd指标》
7 | # qmt量化交易
8 | # 金叉买入,死叉卖出
9 | # 短时间内不重复下单
10 | # 作者威♥: yiyou888wx
11 | # (可开户、代写)
12 | # 量化优势:对抗人性、不用盯盘
13 |
14 | class a():
15 | pass
16 |
17 | A = a()
18 |
19 | def init(C):
20 | # 设置股票代码,上海SH结尾,深圳SZ结尾
21 | A.stock = '000333.SZ'
22 | # 填写自己的账号
23 | A.account = '39001785'
24 | # 设置每次交易的股票数量
25 | A.volume = 100
26 | # 设置k线周期
27 | A.period = '1h'
28 | # 1小时(3600秒)内不重复下单
29 | A.trade_time = 3600
30 | # macd参数配置
31 | # 分别是短周期、长周期、移动平均周期
32 | A.param1,A.param2,A.param3 = 12, 26, 9
33 |
34 | # 代码自动下载有用的历史数据,这样无需手动下载
35 | end = datetime.date.today()
36 | # 根据你的周期来,days可需改
37 | start = end - datetime.timedelta(days=10)
38 | start = start.strftime('%Y%m%d')
39 | end = end.strftime('%Y%m%d')
40 | download_history_data(A.stock, A.period, start, end)
41 |
42 | # 账号、资金情况
43 | account = get_trade_detail_data(A.account, 'STOCK', 'account')
44 | if len(account)==0:
45 | print(f'账号{A.account} 未登录 请检查')
46 | return
47 | account = account[0]
48 | # 可用资金
49 | available_cash = int(account.m_dAvailable)
50 | # 总资金
51 | total_cash = int(account.m_dBalance)
52 | print('【【账户信息】】')
53 | print(f'账户:{A.account}, 总资金:{total_cash}, 可用资金:{available_cash}')
54 |
55 | # 初始化上次成交时间为 None
56 | A.last_trade_time = None
57 |
58 |
59 | def handlebar(C):
60 | # 只处理最新数据传来的时候
61 | if not C.is_last_bar():
62 | return
63 |
64 | now = datetime.datetime.now()
65 | now_time = now.strftime('%H%M%S')
66 | #跳过非交易时间
67 | if now_time < '093000' or now_time > "150000":
68 | return
69 |
70 | stock_data_df = C.get_market_data(['close'],[A.stock], A.period, count=50)
71 | stock_data_closes = np.array(stock_data_df['close'])
72 | #print(f'stock_data_closes:{stock_data_closes[-5:]}')
73 | print(f'股票:{A.stock},当前价格:{stock_data_closes[-1]:.2f}')
74 |
75 | # 数据太少 报错!
76 | if len(stock_data_closes)<50:
77 | print('【错误】k线数据不足,无法计算!')
78 | return
79 | dif, dea, macd = talib.MACD(stock_data_closes, fastperiod=A.param1,
80 | slowperiod=A.param2, signalperiod=A.param3)
81 | #print(f'macd: {macd[-5:]}')
82 |
83 | # 当前时间
84 | current_time = datetime.datetime.now()
85 |
86 | # 金叉
87 | if macd[-2]<0 and macd[-1]>=0:
88 | print(f'进入金叉状态')
89 | # 如果 last_trade_time 为 None,或者距离上次成交时间超过1小时
90 | if A.last_trade_time is None or (current_time - A.last_trade_time).total_seconds() > A.trade_time:
91 | print(f'买入{A.stock}股票,数量:{A.volume},请保证资金充足!')
92 | passorder(23,1101,A.account,A.stock,14,-1,A.volume,2,C)
93 |
94 | # 记录当前时间
95 | A.last_trade_time = current_time
96 | else:
97 | print(f'一小时内有过交易,不再处理')
98 |
99 | # 死叉
100 | if macd[-2]>0 and macd[-1]<=0:
101 | print(f'进入死叉状态')
102 | # 如果 last_trade_time 为 None,或者距离上次成交时间超过1小时
103 | if A.last_trade_time is None or (current_time - A.last_trade_time).total_seconds() > A.trade_time:
104 | print(f'卖出{A.stock}股票,数量:{A.volume},请保证有持仓!')
105 | passorder(24,1101,A.account,A.stock,14,-1,A.volume,2,C)
106 |
107 | # 记录当前时间
108 | A.last_trade_time = current_time
109 | else:
110 | print(f'一小时内有过交易,不再处理')
111 |
--------------------------------------------------------------------------------
/微信群.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JizhiXiang/Quant-Strategy/6871d593e1eceab1a946dfac48b296254cba0de5/微信群.jpg
--------------------------------------------------------------------------------