|
|
51CTO旗下网站
|
|
移动端

2.2.3 高阶函数

《量化交易之路:用Python做股票量化分析》第2章量化语言——Python,第2部分(第2~6章)主要讲解了量化交易需要的基础知识及相关工具,如Python语言、NumPy、pandas、数据可视化及量化数学等知识,适合完全没有任何编程经验的读者从头开始阅读。本节为大家介绍高阶函数。

作者:阿布来源:机械工业出版社|2017-10-19 16:08

2.2.3  高阶函数

常见的高阶函数包括:

map()函数,接收两个参数,一个是函数,一个是序列,map()把传入的函数依次作用于序列的每个元素,并把结果作为新的序列返回;

filter()函数,接收两个参数,一个是函数,一个是序列,filter()把传入的函数依次作用于每个元素,根据返回值是True还是False决定是保留还是丢弃该元素,结果序列是所有返回值为True的子集;

reduce()函数,把一个函数作用在一个序列上,这个函数必须接收两个参数,其中reduce()函数把结果继续和序列的下一个元素做累积计算,reduce()函数只返回值结果非序列。

【需求5】从收盘价格,推导出每天的涨跌幅度。

首先将两两相邻的收盘价格组成tuple后装入list,代码如下:

  1. # 将字符串的价格通过列表推导式显式转换为float类型  
  2. # 由于stock_dict是OrderedDict所以才可以直接  
  3. # 使用stock_dict.values()获取有序日期的收盘价格  
  4. price_float_array = [float(price_str) for price_str in  
  5.                      stock_dict.values()]  
  6. # 通过将时间平移形成两个错开的收盘价序列,通过zip打包成为一个新的序列  
  7. # 通过[:-1]:从第0个到倒数第二个,[1:]:从第一个到最后一个,形成两两前后相邻  
  8. # 组成的序列每个元素为相邻的两个收盘价格  
  9. pp_array = [(price1, price2) for price1, price2 in  
  10.             zip(price_float_array[:-1], price_float_array[1:])]]  
  11. pp_array 

输出如下:

  1. [(30.14, 29.58), (29.58, 26.36), (26.36, 32.56), (32.56, 32.82)] 

上面代码使用[:-1],[1:],在Python中称为切片。

切片:price_float_array[:-1]代表一个切片操作,针对一个序列取指定索引范围的操作叫做切片,[:-1]表示从索引0开始取(如果第一个索引是0,可以省略),直到索引倒数第一个为止,但不包括索引倒数第一,即选取所有索引但不含最后一个。同理,price_float_array[1:],[1:]表示从索引1开始取,直到最后,即选取所有索引但不含第一个。

下面使用高阶函数map()和reduce()结合lambda函数完成需求,推导出每天的涨跌幅度。

外层使用map()函数针对pp_array的每一个元素执行操作,内层使用reduce()函数即两个相邻的价格,求出涨跌幅度,返回外层结果list。

  1. # round将float保留几位小数,以下保留3位  
  2. change_array = map(  
  3.     lambda pp: reduce(lambda a, b: round((b - a) / a, 3), pp),  
  4.     pp_array)  
  5. # list insert插入数据,将第一天的涨跌幅设置为0  
  6. change_array.insert(0, 0)  
  7. change_array 

输出如下:

  1. [0, -0.019, -0.109, 0.235, 0.008] 

将计算出的涨跌幅数据加入OrderedDict,配合使用namedtuple重新构建数据结构stock_dict。

  1. # 使用namedtuple重新构建数据结构  
  2. stock_namedtuple = namedtuple('stock', ('date', 'price', 'change'))  
  3. # 通过zip分别从date_array,price_array,change_array拿数据组成  
  4. # stock_namedtuple然后以date作为key组成OrderedDict  
  5. stock_dict = OrderedDict((date, stock_namedtuple(date, price, change))  
  6.                          for date, price, change in  
  7.                          zip(date_array, price_array, change_array))  
  8.  
  9. stock_dict 

输出如下:

  1. OrderedDict(  
  2.    [('20170118', stock(date='20170118'price='30.14'change=0)),  
  3.     ('20170119', stock(date='20170119'price='29.58'change=-0.019)),  
  4.     ('20170120', stock(date='20170120'price='26.36'change=-0.109)),  
  5.     ('20170121', stock(date='20170121'price='32.56'change=0.235)),  
  6.     ('20170122', stock(date='20170122'price='32.82'change=0.008))]) 

使用高阶函数filter()进行数据筛选,以下代码筛选出上涨的交易日。

  1. up_days = filter(lambda day: day.change > 0, stock_dict.values())  
  2. up_days 

输出如下:

  1. [stock(date='20170121'price='32.56'change=0.235),  
  2. stock(date='20170122'price='32.82'change=0.008)] 

以上代码需要筛选出的是上涨的交易日,但有时可能需要筛选出下跌的交易日,或者需要计算所有上涨的涨幅和数值或下跌的跌幅和数值。下面用一个通用的函数来完成所有需求。

Python中定义默认函数参数的方式和其他语言类似,直接在函数声明中赋予默认值;

Python中用三目表达式替代传统的if和else逻辑写法,使代码更加简洁。

  1. # want_up默认为True, want_calc_sum默认为False  
  2. def filter_stock(stock_array_dict, want_up=Truewant_calc_sum=False):  
  3.     if not isinstance(stock_array_dict, OrderedDict):  
  4.         # 如果类型不符合则产生错误  
  5.         raise TypeError('stock_array_dict must be OrderedDict!')  
  6.  
  7.     # Python中的三目表达式的写法  
  8.     filter_func = (lambda day: day.change > 0) \  
  9.         if want_up else (lambda day: day.change < 0)  
  10.       
  11.     # 使用filter_func作为筛选函数  
  12.     want_days = filter(filter_func, stock_array_dict.values())  
  13.  
  14.     if not want_calc_sum:  
  15.         return want_days  
  16.  
  17.     # 需要计算涨跌幅和  
  18.     change_sum = 0.0  
  19.     for day in want_days:  
  20.         change_sum += day.change  
  21.     return change_sum 

使用示例如下:

  1. # 全部使用默认参数  
  2. print '所有上涨的交易日:{}'.format(filter_stock(stock_dict))  
  3.  
  4. want_up=False 
  5. print '所有下跌的交易日:{}'.format(  
  6.     filter_stock(stock_dict, want_up=False))  
  7.  
  8. # 计算所有上涨的总和  
  9. print '所有上涨交易日的涨幅和:{}'.format(  
  10.     filter_stock(stock_dict, want_calc_sum=True))  
  11.  
  12. # 计算所有下跌的总和  
  13. print '所有下跌交易日的跌幅和:{}'.format(  
  14.     filter_stock(stock_dict, want_up=Falsewant_calc_sum=True)) 

输出如下:

  1. 所有上涨的交易日:[stock(date='20170121'price='32.56'change=0.235), stock(date='20170122'price='32.82'change=0.008)]  
  2. 所有下跌的交易日:[stock(date='20170119'price='29.58'change=-0.019), stock(date='20170120'price='26.36'change=-0.109)]  
  3. 所有上涨交易日的涨幅和:0.243  
  4. 所有下跌交易日的跌幅和:-0.128 

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

Java (JDK 6)学习笔记

Java学习笔记在JavaWorld技术论坛(http://www.javaworld.com.tw/)和作者的网站(http://caterpillar.onlyfun.net/Gossip/)提供免费下载...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊