本文是[量化交易零基础入门教程](https://www.joinquant.com/post/13149)中的一篇,点击蓝字链接可查看该系列详情。
------
### 摘要
- 函数与API
- 函数使用方法
- 如何看API文档
- 自定义函数方法
- 常用的下单函数
- 自测与自学
---
- 我们继续以前文策略代码为例进行讲解,如下:
def initialize(context):
run_daily(period,time='every_bar')
g.security = '000001.XSHE'
def period(context):
order(g.security, 100)
- 通过前文讲解,现在这段代码中就剩这句下单语句还没讲了。为了理解这条语句,需要学习下python中函数的知识。
order(g.security, 100)
### 函数与API
- 函数是封装好的,可重复使用的 ,用来实现专一功能的代码段。函数能使代码易于维护与交流,提高编写策略的效率。通俗的理解是,把一系列代码指令包起来就是一个函数,起个名字就是函数名,之后用这个函数名,就知道这个名字指代那被包起来的一系列代码指令了。
- Python语言自带了许多内建函数,比如之前见过的print()、type()都是Python自带的函数,可以直接用。你也可以自己创建函数自己用,这被叫做自定义函数。比如如下这段框架代码其实就是自定义了一个名为period的函数,该函数内包了一个聚宽系统自带的函数order():
def period(context):
order(g.security, 100)
- order()的准确称谓其实是API(application programming interface,即应用程序编程接口),API的含义与函数有所不同,解释起来略复杂。不过实际使用中跟函数几乎没有差别,可以理解成聚宽平台基于python封装而成的函数。在[聚宽的API文档](https://www.joinquant.com/api)中你可以看到除order()外其他API。
### 使用一个函数
- 在使用函数的时候,通常需要提供一些参数(也有可能不需要),函数根据提供的参数,执行一系列的函数作者设计好的操作,往往也会根据提供的参数返回结果(也可能返回为空,即不返回),如下:
# 用法: 函数名(参数,参数,......)
# 例子如下:
# 提供了两个参数g.security和100,执行了买入g.security中数据对应的股票100股的操作
order(g.security, 100)
# 提供了一个参数"你好",执行了打印"你好"的操作
print("你好")
# 提供了一个参数"1"给type()函数,type函数执行了识别"1"数据类型的操作,并返回了"1"数据类型为结果。
# type返回的结果被当做参数提供给了print(),print执行了打印type返回的结果的操作
# type与print的嵌套使用,实现了打印"1"数据类型的操作。
print(type("1"))
- 可见,函数的功能多种多样,需要参数、返回的结果亦不尽相同,所以具体怎么用需要看函数作者提供的说明文档,或者看函数内的设计代码自己推断。函数内的代码不见得看得到,看到不一定看得懂,想看懂也可能很辛苦。所以一般函数的用法要看函数作者提供的说明文档。
- 聚宽设计的函数(如前文所说准确叫法是API)的用法都写在API文档里,位置在聚宽网站导航栏-帮助-API文档。
- 接下来以order为例讲下文档怎么看。在API文档中找到 [order - 按股数下单](https://www.joinquant.com/api#order-%E6%8C%89%E8%82%A1%E6%95%B0%E4%B8%8B%E5%8D%95)的说明,如下:

- 可以看到,order可接受的参数有5个,分别是security,amount,style,side,pindex,这五个参数的名字与含义是函数作者设计的。意思是你使用order提供参数的时候,被提供参数将**按提供的顺序依次对应**这5个参数。比如下面的写法就是错误的。
# 函数会按顺序把100对应为security,即股票代码,把"000001.XSHE"对应为amount,即要交易的数量。所以就会错。
order(100,"000001.XSHE")
- 不按顺序提供参数的正确写法如下:
# 用等号表示对应关系,参数名写前,要当做参数的变量或数据写在后
# 如下是把100当做amount参数,把"000001.XSHE"当做security参数。
order(amount=100,security="000001.XSHE")
- 可以发现有些参数后面有等号,如style=None,含义style参数不提供的话,会被默认是None,其他的side='long', pindex=0也是一样的道理,如果不提供会被默认是等号后面的内容。所以前文order()只写了两个参数也不会错。注意,security和amount后面没有等号,即没有默认值,则必须提供参数不能省略。
# 以下两句含义相同
order("000001.XSHE",100)
order("000001.XSHE",100,None,'long',0)
- 细说下order的各个参数
- security 标的代码,数据类型要求是字符串,想知道 基金、期货、指数的代码都是什么,可以在这里看[聚宽数据](https://www.joinquant.com/data),比如聚宽数据-向下滚动页面-点击指数数据,可以看到各指数的代码。特别的是股票代码目前没有页面,但只需在平时使用的股票代码后面加后缀就好了,**深交所(深交所股票0开头)股票代码后缀为.XSHE,如000001.XSHE,上交所股票代码(上交所股票6开头)后缀为.XSHG 如600000.XSHG。**
- amount 交易数量, 正数表示买入, 负数表示卖出,没什么可说的。
- style参数决定下的订单是市价单还是限价单,默认是None代表市价单。目前就用默认吧,限价单以后讲。
- side参数决定是开空单还是多单,默认为多单,股票只能多单,股指期货等其他品类可以开空单。
- pindex参数是在多资金仓位时选择资金仓位的,股票一般用不到。
- 根据说明文档,order函数是有返回值的,如果创建订单成功, 则返回Order对象, 失败则返回None。有返回值不一定要用,比如前文的例子都没用到这个返回值,实际上策略做的相当完备的时候才可能用到。一般用法是,根据返回值是否是None,判断是否下单成功,成功时,根据返回值可以查询订单或取消订单等。不过具体实现方法、以及Order对象是什么,还需要学习很多的知识,后续可能会讲到。
### 自定义函数
- Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
- 函数名即为该函数起的名字,函数体即包在函数中的一系列操作的代码,参数列表即使用函数需要提供的参数,比如一个根据圆半径求周长的函数如下:
# 根据圆半径r求周长l
def yuan(r):
p=3.14
l=2*p*r
return l
- return的含义是结束函数的运行并返回一个值,如上例子中就是返回了算好的周长l。如果return后什么也不写就是返回None即空,如果不写return,函数体运行完后,自动return None。
- 至此,你应该意识到,函数内部是相对独立的,数据想进来要通过参数传进来,想出去要通过返回值传出去,函数从获得参数到返回值的过程中所产生的数据与变量中没通过返回值传出去的,在函数运行结束后(即返回值后)都将被计算机释放不再存储。如果想函数间通用某变量可以考虑用之前讲的全局变量。
- 如前文讲使用函数时看到的,可以用等号给参数附加默认值,而且可以用逗号分隔分隔多个参数,例子如下:
# 根据圆半径r求周长l的k分之一
def yuan(r,k=1):
p=3.14
l=2*p*r/k
return l
- 在返回值的时候可以返回多个变量,例子如下:
# 根据圆半径r求周长l与面积s的k分之一
def yuan(r,k=1):
p=3.14
l=2*p*r/k
s=p*r*r/k
return l,s
- 使用自定义函数的方法跟前文讲的使用函数的方法一致,需要说明的是定义函数的代码放的位置,如下:

### 常用的下单函数
- 常用的下单函数有四个,使用方法和order()差不多,可能有人自己看API文档就能学会了。接下来我们分别介绍下基本用法,同样的不讲style,side,pindex这三个参数。
- order(security,amount),刚刚细讲过,含义是买卖一定数量的(单位:股)股票。security是股票代码,amount是数量,amount为负数时就是代表卖出了,需要知道的是,国内股票买入最小单位是1手即100股。例子如下:
# 买入100股平安银行
order("000001.XSHE",100)
# 卖出100股平安银行
order("000001.XSHE",-100)
- order_target(security,amount),含义是通过买卖,将股票仓位调整至一定数量(单位:股)。security是股票代码,amount是数量。例子如下:
# 调整平安银行的持股数量至1000股
# 即,如果目前平安银行的持股数量低于1000股就买入,高于就是卖出,不高不低就不动。
order_target("000001.XSHE",1000)
- order_value(security,value),含义是买卖一定价值量(单位:元)股票。security是股票代码,value是价值量。value为负数时就是代表卖出了。例子如下:
# 买入10000元的平安银行
# 如果当前股票市价是10元,则代表买入1000股
# 如果除不开系统会自动调整成相近的合理数量。卖出时也会。
order_value("000001.XSHE",10000)
# 卖出10000元的平安银行
# 如果当前股票市价是100元,则代表卖出100股
order_value("000001.XSHE",-10000)
- order_target_value(security,value),通过买卖,将股票仓位调整至一定价值量(单位:元)。security是股票代码,value是价值量。例子如下:
# 调整平安银行的持股价值量至10000元
# 即,如果目前平安银行的持股价值量(按股票市价算)低于10000元就买入,高于就是卖出,不高不低就不动。
order_target_value("000001.XSHE",10000)
- 读者在尝试练习使用这些语句的时候,可以点击运行回测,通过查看回测结果页中的交易详情来看语句的执行效果,同时也可以看下日志。如下:


- 股票拆分合并和分红,交易的税费,下单导致成交价向不利的方向波动,这些因素系统都是默认考虑并仿真处理的了,具体的详情以及下的订单系统是如何模拟真实情况撮合成交的,可以看下API文档[订单处理](https://www.joinquant.com/api#%E8%AE%A2%E5%8D%95%E5%A4%84%E7%90%86)。其实新手不用太关注 这些订单处理的细节,不核心,目前也不容易理解,可以等以后自己比较熟悉了再看。
### 自测与自学
- 实践下本文中的例子。
- 搜索了解下移动平均线(MA,均线)的计算方法。
- 搜索了解下市价单、限价单的含义。
- 自定义一个可计算包含若干数list中数的平均值的函数。即如果你定义的函数为pjs(),那么执行pjs([1,3,4,6])后,应该返回平均数3.5。【提示:len()可用来计算list的长度,用法如len([1,2,3,4])】。
---
[查看下一篇](https://www.joinquant.com/post/13169)
写得很好。适合我等小白。感谢了。
有个问题,
在讲到“自定义函数“时,最后一段话“*使用自定义函数的方法跟前文讲的使用函数的方法一致,需要说明的是定义函数的代码放的位置,如下:*”
我看了一下图片,不明白这里有什么特别之处。请赐教。
另外,为什么深圳股票的代码后缀是“XSHE”?上海的是“XSHG”?有什么含义吗?
2018-06-29
@cd6003 你应该是之前有一点编程知识的。API与函数不用定义直接用就行,但自定义的函数需要写代码去定义,所以我是想说明代码写在哪里。
股票的代码后缀可能有原因,是什么的缩写之类的,但我没探究过,而且貌似也不是聚宽命名的,我不知道。
2018-06-30
自定义一个可计算包含若干数list中数的平均值的函数。即如果你定义的函数为pjs(),那么执行pjs([1,3,4,6])后,应该返回平均数3.5。【提示:len()可用来计算list的长度,用法如len([1,2,3,4])】。
老师,这个应该怎么写
2018-07-21
@cd6003 XSHE是国际标准的ISO Market Identification Code
2018-08-13
![NXG3W1Y~M5WBR)L72}MR_NO.png][1]
[1]: https://image.joinquant.com/a18cafe3e5434173bb7b50cdd41e6381
请问定义函数部分的代码段,就是大框的部分,可以放在任何位置吗。有没有什么具体要求.
2018-08-20
这个没有具体要求,按照python的写法来就行,策略中一般将初始化函数放在最前面
2018-08-20
@点量你的交易 暂时你可以理解为写在最外层,即def要顶格写,顺序在period和initialize前后都可以。其实深入一点点了解以后,你会发现函数是有作用域的而且可以嵌套,
2018-08-21
小白想问问,如果我是以某个价格,卖出或买入某个数量的股票,那应该调用那个函数
还有就是有成交回调么,就是告诉我我order后最终的成交价和成交量
2018-08-22
@独来du往de猫 1,下单有多种方式,您讲的可以用 order( '标的代码',数量(股) ,LimitOrderStyle(价格) ) 具体可以看一下 api中的下单函数 和 限价单
2,成交的数据可以在日志或者点击运行回测后的交易详情中找到
2018-08-23
@薛定谔の喵 谢谢大大指导,看到order的范例中有限价单的,当时看了style想找除了None还有那些,一下子漏了范例了:)
2018-08-24
def psj(tlist):
a=float(sum(tlist))
b=float(len(tlist))
average=float(a/b)
print average
print a
print b
2018-08-27
def ma(security,count,unit = '1d',fields,c):
demo = attribute_history(security,count,unit,fields)
movingaverage = demo[c].mean()
return movingaverage
2018-09-03
交作业~
```
def pjs(list1):
Sum=0
a = 0
for i in list1:
if type(i) == int or type(i) == float:
Sum = Sum+i
a = a+1
average = Sum/a
return Sum,average
```
2018-09-03
![微信图片_20180913154524.png][1]
[1]: https://image.joinquant.com/3dedd8ae8b65f1dd4f1fc0b1f7e582b5
为什么这个不是买够了10000块就不买入了?还有这个策略没有定义什么时候下单,是不是系统默认了怎么下单?
2018-09-13
import jqdata
def initialize(context):
g.security = '000001.XSHE'
run_daily(daily, '10:00')
def daily(context):
order(g.security,100)
print(pjs([1,3,4,6,7,9,88]))
def pjs(a):
#a=[1,3,4,6]
b=len(a)
sum = 0.0
#取a中的每一个值
# for i in a:
# print(i)
#通过下标来取值
for i in range(b):
#print(a[i])
sum=sum+a[i]
#print(sum)
c=sum/b
return c
#print(c)
2018-09-16
import jqdata
def initialize(context):
g.security = '000001.XSHE'
run_daily(daily, '10:00')
def daily(context):
order(g.security,100)
print(pjs([1,3,4,6,7,9,88]))
def pjs(a):
#a=[1,3,4,6]
b=len(a)
sum = 0.0
#取a中的每一个值
# for i in a:
# print(i)
#通过下标来取值
for i in range(b):
#print(a[i])
sum=sum+a[i]
#print(sum)
c=sum/b
return c
#print(c)
2018-09-16
@yuetao1202 请问您算出来的结果正确吗?
2018-09-22
@yasu pjs([1,2,3.3,2.9]),带入数值计算没问题呀~
(9.2, 2.3),前面是总和,后面是平均数
2018-09-22
@yuetao1202 噢噢~之前我算了算,算错叻,后来发现是因为浮点数精度问题,大大程序没错,受教受教,谢谢大大~:-D
2018-09-24