第二章 量化交易的基础(1)

2.1 基础语法与数据结构

  • 无用的变量 Python 建议使用 '_' 声明:
price_array = ['30.14', '29.58', '26.36', '32.56', '32.82']

date_base = 20170118
date_array = [str(date_base + ind) for ind, _ in enumerate(price_array)]

date_array =
['20170118', '20170119', '20170120', '20170121', '20170122']

  • 可命名元组:namedtuple
from collections import namedtuple

stock_namedtuple = namedtuple('stock', ('date', 'price'))
stock_namedtuple_list = [stock_namedtuple(date, price) for date, price in
                         zip(date_array, price_array)]
# namedtuple 访问 price
print('20170119日的价格:{}'.format(stock_namedtuple_list[1].price))
print(stock_namedtuple_list)

20170119日的价格:29.58
[stock(date='20170118', price='30.14'),
stock(date='20170119', price='29.58'), ...]

  • 字典推导式
# 字典推导式:{key: value for in}
stock_dict = {date: price for date, price in zip(date_array, price_array)}
print('20170119日的价格:{}'.format(stock_dict['20170119']))
print(stock_dict)

20170119日的价格:29.58
{'20170118': '30.14', '20170119': '29.58', ...}
*字典的存储是无序的

  • 有序字典:Orderdict
from collections import OrderedDict
stock_dict = OrderedDict((date, price) for date, price in zip(date_array, price_array))
print(stock_dict.keys())

odict_keys(['20170118', '20170119', '20170120', '20170121', '20170122'])

2.2 函数

1. 内置函数

需求3:从前面组合的字典数据中找到最小的一个收盘价格。

min_price = min(zip(stock_dict.values(), stock_dict.keys()))

min_price = ('26.36', '20170120')

2. 自定义函数

需求4:计算所有收盘价格中第二大的价格元素。

def find_second_max(dict_array):
    # 对传入的 dict sorted 排序
    stock_price_sorted = sorted(zip(dict_array.values(), dict_array.keys()))
    # 第二大值的函数也就是倒数第二个
    return stock_price_sorted[-2]

# 系统函数 callable() 验证是否为一个可调用(call)的函数
if callable(find_second_max):
    print(find_second_max(stock_dict))

结果:('32.56', '20170121')

3. lambda 函数

上边使用 lambda 匿名函数直接定义更加简洁:

find_second_max_lambda = lambda dict_array: \
    sorted(zip(dict_array.values(), dict_array.keys()))[-2]
print(find_second_max_lambda(stock_dict))  

结果:('32.56', '20170121')

  • 以上代码 lambda 函数赋给了一个变量 ,可以这样操作的原因是 Python 里一切皆为对象,所以函数也是一个对象。这个特点可以帮助开发者完成其他语言中一些很复杂的操作。
  • Python 中的函数可以返回多个返回值,但实际上仍然是一个返回值,只不过返回值通过打包为 tuple 队列,实现多个返回值。
4. 高阶函数
  • map():两个参数,一个是函数,一个是序列,map() 把传入的函数依次作用于序列的每个元素,把结果作为新的序列返回;
  • filter():接收两个参数,一个是函数,一个是序列, filter() 把传入的函数依次作用于每个元素,根据返回值是 True 还是 False 决定是保留还是丢弃该元素,结果序列是所有返回值为 True 的子集;
  • reduce():把一个函数作用在一个序列上,这个函数必须接收两个参数,其中 reduce() 函数把结果继续和序列的下一个元素做累积计算, reduce() 函数只返回值结果非序列。
    需求5:从收盘价格,推导出每天的涨跌幅度。
pp_array = [(price1, price2) for price1, price2 in
            zip(price_float_array[:-1], price_float_array[1:])]

结果:[(30.14, 29.58), (29.58, 26.36), (26.36, 32.56), (32.56, 32.82)]

下面使用高阶函数 map() 和 reduce() 结合 lambda 函数完成需求, 推导l士i每天的涨跌 幅度。 外层使用 map() 函数针对 pp_array 的每一个元素执行操作,内层使用 reduce() 函数即 两个相邻的价格,求出涨跌幅度,返回外层结果 list。

from functools import reduce
# round 将 float 保留几位小数,以下保留3位
change_array = list(map(lambda pp: reduce(lambda a, b: round((b-a)/a, 3), pp), pp_array))
# list insert 插入数据,降低一天的涨跌幅设置为0
change_array.insert(0, 0)
print(change_array)

涨跌幅数据:[0, -0.019, -0.109, 0.235, 0.008]

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

# 使用 namedtuple 重新构建数据结构
stock_namedtuple = namedtuple('stock', ('date', 'price', 'change'))
# 通过 zip 分别从 date_array, price_array, change_array 拿数据组成
# stock_namedtuple 然后以 date 作为 key 组成 OrderedDict
stock_dict = OrderedDict((date, stock_namedtuple(date, price, change))
                         for date, price, change in
                         zip(date_array, price_array, change_array))
print(stock_dict)

结果:
OrderedDict([('20170118', stock(date='20170118', price='30.14', change=0)),
('20170119', stock(date='20170119', price='29.58', change=-0.019)), ...])

  • 定义一个通用函数完成所有需求:筛选上涨/下跌,计算所有 上涨/下跌 的 涨/跌幅 和数值。
def filter_stock(stock_array_dict, want_up=True, want_calc_sum=False):
    if not isinstance(stock_array_dict, OrderedDict):
        raise TypeError('stock_array_dict must be OrderedDict!')

    # python 中的三目表达式的写法
    filter_func = (lambda day: day.change > 0) \
        if want_up else (lambda day: day.change < 0)
    want_days = list(filter(filter_func, stock_array_dict.values()))
    if not want_calc_sum:
        return want_days

    # 计算涨跌幅和
    change_sum = 0.0
    for day in want_days:
        change_sum += day.change
    return change_sum

print('所有上涨的交易日:{}'.format(filter_stock(stock_dict)))
print('所有下跌的交易日:{}'.format(filter_stock(stock_dict, want_up=False)))
print('所有上涨交易日的涨幅和:{}'.format(filter_stock(stock_dict, want_calc_sum=True)))
print('所有下跌交易日的跌幅和:{}'.format(filter_stock(stock_dict, want_up=False, want_calc_sum=True)))
  • 所有上涨的交易日:
    [stock(date='20170121', price='32.56', change=0.235), stock(date='20170122', price='32.82', change=0.008)]
  • 所有下跌的交易日:
    [stock(date='20170119', price='29.58', change=-0.019), stock(date='20170120', price='26.36', change=-0.109)]
  • 所有上涨交易日的涨幅和:0.243
  • 所有下跌交易日的跌幅和:-0.128
5. 偏函数

前面示例中的 filter_stock() 由于参数太多,很容易使用时产生错误。使用 functools.partial() 可以创建一个新的函数,从而在调用时更简单,函数功能也更加明确。

from functools import partial

# 筛选上涨交易日
filter_stock_up_days = partial(filter_stock, want_up=True, want_calc_sum=False)
print('所有上涨的交易日:{}'.format(filter_stock_up_days(stock_dict)))
  • 所有上涨的交易日:
    [stock(date='20170121', price='32.56', change=0.235), stock(date='20170122', price='32.82', change=0.008)]

你可能感兴趣的:(第二章 量化交易的基础(1))