# 1 有关策略运行及频率的说明
- 聚宽的回测环境本来就是一个Pyhton编辑器编辑完成后会自动保存点击编辑运行或者运行回测后系统会自动编译及运行代码
- 有关策略的运行请查看我们[策略程序架构](https://www.joinquant.com/help/api/help?name=api#策略程序架构♦)
-如果策略中有定义[策略程序架构](https://www.joinquant.com/help/api/help?name=api#策略程序架构♦)中的函数,则系统会自动在相应的时间调用这些函数。
-如果策略中自定义的函数有通过[run_daily/run_weekly/run_monthly](https://www.joinquant.com/help/api/help?name=api#run_daily)进行注册,则根据注册时的参数,系统会自动以固定的频率(时间)调用注册的函数。
-如果用户自定义的函数没有进行注册,且函数名不属于[策略程序架构](https://www.joinquant.com/help/api/help?name=api#策略程序架构♦)中的函数,则系统不会主动调用。
-注意:如果是使用[策略程序架构](https://www.joinquant.com/help/api/help?name=api#策略程序架构♦)中的函数,请严格按照api中的参数进行定义。如果要自定义函数,请避免使用和API中的函数名,否则将引起报错。
- 策略的运行频率有天、分钟、tick三个级别策略频率的选择方法如下图所示其中tick频率需要[会员开通tick权限](https://www.joinquant.com/view/vip/charge)或者[使用积分兑换tick权限](https://www.joinquant.com/view/credits/detail/5e1e858651cc4a12cdf8829957c322bf)。

- 策略运行对应的API有run_daily, run_monthly, run_weekly, hanfle_data, handle_tick 具体的请查看官网API中[定时运行](https://www.joinquant.com/help/api/help?name=api#run_daily
)
- 数据的频率有月、周、天、小时、三十分钟等等具体的查看API中[数据获取函数](https://www.joinquant.com/help/api/help?name=api#数据获取函数)
- 策略运行频率与获取数据的频率是独立的即在策略的运行频率为分钟为天或者tick时也可以时您可以获取周、天、分钟、tick数据
# 2 run_daily, run_weekly, run_monthly解析
## 2.1 run_daily
量化平台不同于程序化交易软件, 许多地方都是用户可以自己定义的。
* **在策略中数据频率和运行频率是两个不同的概念**:
运行频率可以理解为函数的调用频率,也就是您多久去看一眼K线图。
数据频率可以理解为K线的级别,1m的K线,5m的K线或者日线。
这两者之间并没有必然关系,可以在日级别的策略中提取5m的数据,也可以在分钟级别的策略中调用日K数据
* 运行频率:从整个策略层面上讲,平台有三种不同粒度的频率,分别为(天,分钟,tick),频率的选择对策略的主要影响有:
### 2.1.1 天级别:
- run_daily设置time='every_bar'时,设置的函数会在每天开盘时运行(具体开盘时间点和参考标的有关,默认为09:30)一次。
- handle_data的执行时间为09:30时执行一次。
- 限价单挂单时的撮合发生在16:00,可能对资金使用有影响,所以不建议在天级别的策略中使用限价单。
### 2.1.2 分钟级别
- run_daily设置time='every_bar'时,设置的函数会交易时间段的每个分钟运行一次。(交易时间段由参考标的决定,默认为股票的交易时间段)
- handle_data在股票的交易时间段中每分钟执行一次。
- 限价单在每个bar都会撮合一次,账户信息等实时变动。
### 2.1.3 tick级别
- run_daily不能设置time='every_bar',如果设置,该函数不生效。
- handle_data不生效,应该使用handle_tick替代。
- handle_tick每个tick事件产生时都会被执行一遍,
比如一共订阅了两个标的A和B,在'09:31:23'这个点,A和B都产生了一条tick,那么handle_tick将被执行两次,handle_data(context,tick)中的tick对象将分别是A和B的current_tick。
- tick策略中,run_daily中time的参数精度可以精确到秒,分钟及天级别的策略精确到分
___
当然,上边所提到的是平台提供的最基础的策略频率,大家也可以根据上述策略的最小粒度选择高于当前粒度的频率进行回测,最常用的就是定时器了。
### 2.1.4 自定义运行频率示例
一般来讲,自定义运行频率可以使用三种方法,一种就是通过定时器去判断执行次数,在一定的执行次数下再执行后边需要执行的代码;第二种是判断时间,当当前时间的分钟是某个数字的倍数时再运行,比如现在是09:50,50是10的倍数,执行,否则跳过;第三种是直接设置多个定时运行。
eg1. 定时器:
``` python
def initialize(context): #这里选择策略频率为分钟,所以func函数每分钟都会执行一次
run_daily(my_func, 'every_bar',reference_security='AG9999.XSGE')
g.run_num = -1 #初始化计数器,不要在盘中开启策略
def my_func(context):
g.run_num += 1
if g.run_num!=15: #如果这次运行的次数不是15,打断此次运行
return
else:
g.run_num=0 #条件满足,计数器归零,继续后边的代码
print '后边的代码将每隔15分钟运行一次'
```

eg2. 时间判断:
```python
def initialize(context):
run_daily(run_15m, 'every_bar',reference_security='AG1901.XSGE')
def run_15m(context):
if context.current_dt.minute != 0: #如果当前分钟不能整除15,打断此次运行
return
print '下边的代码每15m运行一次'
```

eg3. 多个定时运行:
```python
def initialize(context):
run_time(30)#每30分钟运行一次
def run_time(x):
datas = get_price('000300.XSHG',count=240,frequency='1m').index.tolist()[:-1]#剔除15:00
times = [str(t)[-8:] for t in datas] #提取交易时间
times.insert(0,'09:30:00')
for t in times[::x]:
run_daily(run_min, t) #对某个函数设置多个运行时间点
def run_min(context):
'''需要运行的函数或代码放在这里'''
print 'run'
```

------
### 2.1.5 关于定时运行
常用的有几种运行方法:
- handle_data(context, data) :不需要设置,也并非必须,当定义了程序就会去调用它。一般用于股票策略(也可用于股指期货)。
- handle_tck(context, data) : 不需要进行设置,tick级别策略的专用函数,当定义了程序就会去调用它,每个tick时间发生时运行一次。
- run_daily(func,time,reference_security) :
在初始化中进行设置,和handle_data二选一,非必须,在初始化中进行调用,func是函数名;
time可以选择一个具体时间,也可以选择为'every_bar',当time='every_bar'时,设置的函数会在每个bar(分钟级策略为每分钟,天级别策略为每天开盘,tick级策略不运行)执行一次。
reference_security为可选参数,代表交易时间的参考标的,当time='every_bar'时,运行时间受此影响(默认为股票交易时间)
当然,调用run_daily时必须定义一个函数名和run_daily第一个参数相同的函数,且这个函数只接受一个参数:context
数据获取的粒度直接查看API文档说明就可以了,选择自己需要的frequency或者unit参数,[数据获取函数API](https://www.joinquant.com/help/api/help?name=api#数据获取函数), 获取bar数据请使用get_bars。
数据提取逻辑: https://www.joinquant.com/post/14183
****
大于天级别的,我们可以借助[run_monthly(每月运行一次)和run_weekdly(每周运行一次)](https://www.joinquant.com/help/api/help?name=api#run_daily)去执行某个函数,也可以参考eg1的方法固定每X个交易日运行一次。
## 2.2 run_weekly运行逻辑
`run_weekly(func, weekday, time='9:30', reference_security='000300.XSHG',force=True)`
* func: 需要注册的函数,该函数只接受一个参数context。
* weekday:每周的第几个交易日, 可以是负数, 表示倒数第几个交易日。
* time: 具体执行时间。
* reference_security:参考标的。
* force: 若注册函数的时间晚于函数第一次执行的时间,是否就近执行,默认为True。
### 逻辑梳理: 以注册函数周二运行为例
**force =True **
- 如果注册未周一,则从本周开始,每周周2调用一次func
- 如果注册时间为周二,三,四的某一天,则注册的下一交易日会调用一次func,后续每周周二调用一次func
- 如果注册时间为周五,则本周周五调用一次func,后续每周周二调用一次func
** force =False**
- 如果注册当天未超过周二,则从本周开始每周周二调用一次func
- 如果注册当天为周二,则注册当天调用一次func,后续每个周2调用一次
- 如果注册当天已经超过了周二,则等待下一周开始每个周2调用func,本周不调用func
***
## 2.2 run_monthly运行逻辑
`run_monthly(func, monthday, time='9:30', reference_security='000300.XSHG',force=True)`
* func: 需要注册的函数,该函数只接受一个参数context。
* monthday:每月的第几个交易日, 可以是负数, 表示倒数第几个交易日。
* time: 具体执行时间。
* reference_security:参考标的。
* force: 若注册函数的时间晚于函数第一次执行的时间,是否就近执行,默认为True。
### 逻辑梳理: 以注册函数每月第15个交易日为例
** force =True **
- 如果注册时间为当月第1个交易日,则会在本月第15个交易日调用func,从下月开始每月的第15个交易日调用func
- 如果注册时间为当月第2个交易日,则会在本月第16个交易日调用func,从下月开始每月的第15个交易日调用func
- 以此类推,如果注册日期向后推不足15个交易日,则本月最后一个交易日调用一次func,从下月开始每月的第15个交易日调用func
**force =False**
- 注册时间在本月第15个交易日之前,则本月第15个交易日调用一次func
- 注册时间为本月第15个交易日,则从本月开始,每月调用一次func
- 注册时间在本月第15个交易日之后,本月不调用,下月开始每月第15个交易日调用一次func
# 3 相关链接
- [回测过程](https://www.joinquant.com/help/api/help?name=api#回测过程)
- [运行频率](https://www.joinquant.com/help/api/help?name=api#运行频率)
- [运行时间](https://www.joinquant.com/help/api/help?name=api#运行时间)

这里的代码写错了
2019-10-29

为啥没有每天的最后一分钟15:00的数据
2020-02-08
@JoinQuant-Supercritical 即在策略的运行频率为分钟为天或者tick时也可以时您可以获取周、天、分钟、tick数据
2020-10-10