├── 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 --------------------------------------------------------------------------------