最近在家没啥事,写点量化的代码,下面的代码全部复制了放在掘金量化的一个新建的策略里就能运行,main函数的token 换成你自己的token就行,在系统设置里有token。
可以调参试试,也许可以增加收益。大致思路是:网格交易 下降买的多 上升卖得少 且ATR高减仓。ATR有点鸡肋,好像一直都很低,没有帮助提高收益,去掉也行。
总之年化17%左右,还是不错滴,仅供参考。
```python
# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
from datetime import time, datetime, timedelta
# 定义交易时间和中国节假日
TRADING_HOURS_START = time(9, 31)
TRADING_HOURS_END = time(15, 0)
HOLIDAYS = [
"2022-01-01", "2022-02-11", "2022-02-12", "2022-02-13",
"2022-04-05", "2022-05-01", "2022-06-12", "2022-09-21"
]
def is_trading_time(current_time):
return TRADING_HOURS_START <= current_time.time() <= TRADING_HOURS_END and current_time.weekday() < 5 and current_time.strftime('%Y-%m-%d') not in HOLIDAYS
def init(context):
print("Init function called")
context.stock = 'SHSE.601088' #'SHSE.601088'
context.buy_today = set() # 记录今天买入的股票
context.initial_cash = 200000
context.opening_day = True # 判断是否是策略开始的第一天
context.buy_grid_interval = 0.01 # 1%
context.sell_grid_interval = 0.03 # 1.5%
context.grid_range = [16, 34]
context.last_grid = None
context.grid_volume = 100 # 每次买/卖一手
context.atr_list = [] # 用于存储近14日的ATR
# 记录策略开始日期
#context.start_date = datetime.now()
context.start_date = datetime.strptime('2022-01-04 10:00:00', '%Y-%m-%d %H:%M:%S')
subscribe(context.stock, '1d')
def adjust_volume_to_sell(volume_to_sell, current_holding_volume):
# 将 volume_to_sell 向下取整为100的倍数
volume_to_sell = (volume_to_sell // 100) * 100
# 确保卖出数量不超出持仓数量
volume_to_sell = min(volume_to_sell, current_holding_volume)
return volume_to_sell
def on_bar(context, bars):
#print("On bar function called")
#current_time = datetime.now()
bar = bars[0]
current_time = bar['eob'] # 从bar中获取时间 当前交易时间 不是今天时间
current_time = current_time.replace(hour=10, minute=0, second=0, microsecond=0)
current_time = current_time.replace(tzinfo=None)
#print('current_time:',current_time)
if not is_trading_time(current_time):
return
current_price = bar['close']
# 计算ATR
if len(context.atr_list) >= 14:
context.atr_list.pop(0)
high, low, prev_close = bar['high'], bar['low'], bar['prev_close']
if prev_close is None:
# handle this situation, for example:
prev_close = 0 # or some other default value, or just return
tr = max(high - low, abs(high - prev_close), abs(prev_close - low))
context.atr_list.append(tr)
if context.opening_day:
# 使用50%的初始资金来购买股票
order_value = context.initial_cash * 0.50
volume_to_buy = int(order_value / current_price)
order_target_volume(context.stock, volume_to_buy, order_type=OrderType_Market, position_side=PositionSide_Long)
context.buy_today.add(context.stock)
context.opening_day = False
context.initial_price = current_price
context.last_grid = 0
elif len(context.atr_list) == 14:
atr = sum(context.atr_list) / 14
#current_atr = atr / prev_close # 当前的波动率
if prev_close == 0:
current_atr = 0 # 或者其他你认为合适的默认值
else:
current_atr = atr / prev_close
print('波动率', current_atr)
# 获取账户信息
account_info = context.account()
cash_available = account_info.cash['available']
#total_equity = account_info.equity_value
#fund_usage_ratio = 1 - (cash_available / total_equity)
# 获取股票的持仓情况
stock_position = account_info.position(symbol='SHSE.601088',side = PositionSide_Long) # 假设您是查询多头持仓
if stock_position is not None:
# 从stock_position中取出持仓数量
stock_volume = stock_position['volume']
# 计算该股票的总市值
stock_value = stock_volume * current_price
else:
# 没有持仓
stock_volume = 0
stock_value = 0
#vstock_volume = stock_position['volume']
#stock_value = stock_volume * current_price # 这是该股票的总市值
#print('stock_value', stock_value)
# 计算总权益
total_equity = cash_available + stock_value
#print('cash_available', cash_available)
# 计算资金使用率
fund_usage_ratio = 1 - (cash_available / total_equity)
print('fund_usage_ratio', fund_usage_ratio)
#print('Profit since start:', (current_price - context.initial_price) / context.initial_price)
#print('Days since start:', (current_time - context.start_date).days)
# 判断策略是否运行超过一个月并且资金已经占用了90%
if (current_time - context.start_date).days > 30 and fund_usage_ratio > 0.5:
if current_atr > 0.02: # 这里的0.02是示例,可以根据实际情况调整
profit_threshold = 0.30
else:
profit_threshold = 0.20
# 判断是否达到减仓条件
if (current_price - context.initial_price) / context.initial_price >= profit_threshold:
# positions = context.account().positions()
# for p in positions:
# if p['sec_id'] == context.stock:
# volume_to_sell = int(p['volume'] * 0.25) # 减少25%的持仓
volume_to_sell=int(stock_volume* 0.25) # 减少25%的持仓
# 假设你已经计算得到了一个 volume_to_sell
volume_to_sell2 = adjust_volume_to_sell(volume_to_sell, stock_volume)
order_volume(context.stock, volume_to_sell2, side=OrderSide_Sell,order_type=OrderType_Market,position_effect=PositionEffect_Close,price=0)
print('volume_to_sell', volume_to_sell2)
# 根据价格变化计算网格
price_change = (current_price - context.initial_price) / context.initial_price
current_grid = 0
if price_change < 0:
current_grid = int(price_change / context.buy_grid_interval)
else:
current_grid = int(price_change / context.sell_grid_interval)
if current_grid < context.last_grid:
# 价格下跌,买入
volume_to_order = context.grid_volume * (context.last_grid - current_grid)
order_volume(context.stock,volume=volume_to_order, side=OrderSide_Buy, order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)
context.buy_today.add(context.stock)
context.last_grid = current_grid
elif current_grid > context.last_grid and context.stock not in context.buy_today:
# 价格上涨,卖出
volume_to_order = context.grid_volume * (current_grid - context.last_grid)
order_volume(context.stock, volume_to_order, side=OrderSide_Sell,order_type=OrderType_Market,position_effect=PositionEffect_Close,price=0)
context.last_grid = current_grid
# 一天结束,清空今日购买的记录
context.buy_today.clear()
def on_backtest_end(context):
# 获取回测过程中每一天的净值数据
history_data = context.account().history_net_value()
# 获取最后一天的净值
final_value = history_data[-1]['equity']
# 计算收益率
return_rate = (final_value - context.initial_cash) / context.initial_cash * 100
# 打印收益率
print("最终收益率: {:.2f}%".format(return_rate))
if __name__ == '__main__':
run(strategy_id='strategy_id',
filename='main.py',
mode=MODE_BACKTEST,
token='1999977b75cd379613ac5e4df352a8516f9c6190',
backtest_start_time='2022-01-04 10:00:00',
backtest_end_time='2023-09-24 16:00:00',
backtest_adjust=ADJUST_PREV,
backtest_initial_cash=200000,
backtest_commission_ratio=0.0004,
backtest_slippage_ratio=0.0001)