Python 算法交易秘籍(一)(1)https://developer.aliyun.com/article/1523065
工作原理…
在步骤 1中,您从datetime
模块导入date
、datetime
和timedelta
类。在步骤 2中,您使用类date
提供的today()
classmethod
获取今天的日期,并将其赋值给一个新属性date_today
。(classmethod
允许您直接在类上调用方法而不创建实例。)返回的对象类型为datetime.date
。在步骤 3中,您通过将持续时间为 5 天的timedelta
对象添加到date_today
来创建一个比今天晚 5 天的日期。您将此赋值给一个新属性date_5days_later
。同样,在步骤 4中,您创建一个 5 天前的日期并将其赋值给一个新属性date_5days_ago
。
在步骤 5 和 步骤 6 中,你使用 >
和 <
操作符分别比较 date_5days_later
和 date_5days_ago
。如果第一个操作数保存的日期在第二个操作数之后,则 >
操作符返回 True
。类似地,如果第二个操作数保存的日期在第一个操作数之后,则 <
操作符返回 True
。在 步骤 7 中,你比较到目前为止创建的所有三个日期对象。注意输出。
步骤 8 到 步骤 14 执行与 步骤 2 到 步骤 7 相同的操作,但这次是在datetime.time
对象上——获取当前时间、获取当前时间之后的 5 分钟、获取当前时间之前的 5 分钟,并比较所有创建的datetime.time
对象。无法直接将timedelta
对象添加到datetime.time
对象中以获取过去或未来的时间。为了克服这一点,你可以将timedelta
对象添加到datetime
对象中,然后使用time()
方法从中提取时间。你在 步骤 10 和 步骤 11 中执行此操作。
还有更多
本示例展示了对date
和time
对象的操作,这些操作可以类似地在datetime
对象上执行。除了+
、-
、<
和>
之外,你还可以在datetime
、date
和time
对象上使用以下操作符:
>= |
仅在第一个操作数保持的datetime /date /time 晚于或等于第二个操作数时返回True |
<= |
仅在第一个操作数保持的datetime /date /time 早于或等于第二个操作数时返回True |
== |
仅在第一个操作数保持的datetime /date /time 等于第二个操作数时返回True |
这不是允许的操作符的详尽列表。有关更多信息,请参阅datetime
模块的官方文档:docs.python.org/3.8/library/datetime.html
。
修改 datetime 对象
通常,你可能希望修改现有的datetime
对象以表示不同的日期和时间。本示例包括演示此操作的代码。
如何做…
按照以下步骤执行此示例:
- 从 Python 标准库中导入必要的模块:
>>> from datetime import datetime
- 获取当前时间戳。将其分配给
dt1
并打印:
>>> dt1 = datetime.now() >>> print(dt1)
我们得到以下输出。你的输出会有所不同:
2020-08-12 20:55:46.753899
- 通过替换
dt1
的year
、month
和day
属性来创建一个新的datetime
对象。将其分配给dt2
并打印:
>>> dt2 = dt1.replace(year=2021, month=1, day=1) >>> print(f'A timestamp from 1st January 2021: {dt2}')
我们得到以下输出。你的输出会有所不同:
A timestamp from 1st January 2021: 2021-01-01 20:55:46.753899
- 通过直接指定所有属性来创建一个新的
datetime
对象。将其分配给dt3
并打印它:
>>> dt3 = datetime(year=2021, month=1, day=1, hour=dt1.hour, minute=dt1.minute, second=dt1.second, microsecond=dt1.microsecond, tzinfo=dt1.tzinfo) print(f'A timestamp from 1st January 2021: {dt3}')
我们得到以下输出。你的输出会有所不同:
A timestamp from 1st January 2021: 2021-01-01 20:55:46.753899
- 比较
dt2
和dt3
:
>>> dt2 == dt3
我们得到以下输出。
True
工作原理…
在步骤 1中,您从datetime
模块中导入datetime
类。在步骤 2中,您使用datetime
的now()
方法获取当前时间戳并将其赋值给新属性dt1
。要从现有的datetime
对象获取修改后的时间戳,可以使用replace()
方法。在步骤 3中,您通过调用replace()
方法从dt1
创建一个新的datetime
对象dt2
。您指定要修改的属性,即year
、month
和day
。其余属性保持不变,即hour
、minute
、second
、microsecond
和timezone
。您可以通过比较步骤 2和步骤 3的输出来确认这一点。在步骤 4中,您创建另一个datetime
对象dt3
。这次,您直接调用datetime
构造函数。您将所有属性传递给构造函数,使创建的时间戳与dt2
相同。在步骤 5中,您使用==
运算符确认dt2
和dt3
持有完全相同的时间戳,该运算符返回True
。
将datetime
对象转换为字符串
本配方演示了将datetime
对象转换为字符串的过程,该过程在打印和日志记录中应用。此外,在通过 web API 发送时间戳时也很有帮助。
如何做…
执行此配方的以下步骤:
- 从 Python 标准库中导入必要的模块:
>>> from datetime import datetime
- 获取带有时区信息的当前时间戳。将其分配给
now
并打印出来:
>>> now = datetime.now().astimezone()
- 将
now
强制转换为字符串并打印出来:
>>> print(str(now))
我们得到以下输出。您的输出可能会有所不同:
2020-08-12 20:55:48.366130+05:30
- 使用
strftime()
将now
转换为具有特定日期时间格式的字符串并打印出来:
>>> print(now.strftime("%d-%m-%Y %H:%M:%S %Z"))
我们得到以下输出。您的输出可能会有所不同:
12-08-2020 20:55:48 +0530
如何运作…
在步骤 1中,您从datetime
模块中导入datetime
类。在步骤 2中,您使用带有时区的当前时间戳并将其赋值给新属性now
。datetime
的now()
方法获取当前时间戳,但没有时区信息。这样的对象称为时区本地的datetime
对象。astimezone()
方法从此时区无关对象上添加系统本地时区的时区信息,从而将其转换为时区感知对象。(有关更多信息,请参阅datetime 对象和时区配方)。在步骤 3中,您将now
转换为字符串对象并将其打印出来。请注意,输出的日期格式是固定的,可能不是您的选择。datetime
模块有一个strftime()
方法,它可以按需要将对象转换为特定格式的字符串。在步骤 4中,您将now
转换为格式为DD-MM-YYYY HH:MM:SS +Z
的字符串。步骤 4中使用的指令描述如下:
指令 | 意义 |
%d |
以零填充的十进制数表示的月份中的一天 |
%m |
以零填充的十进制月份 |
%Y |
十进制数世纪年份 |
%H |
小时(24 小时制)以零填充的十进制数 |
%M |
分钟,以零填充的十进制数 |
%S |
秒,以零填充的十进制数 |
%Z |
时区名称(如果对象是无时区的,则为空字符串) |
可以在docs.python.org/3.7/library/datetime.html#strftime-and-strptime-behavior
找到可以提供给.strptime()
的指令的完整列表。
从字符串创建 datetime 对象
此配方演示了将格式良好的字符串转换为datetime
对象。这在从文件中读取时间戳时很有用。此外,在通过 Web API 接收时间戳作为 JSON 数据时也很有帮助。
如何做…
执行此配方的以下步骤:
- 从 Python 标准库中导入必要的模块:
>>> from datetime import datetime
- 创建一个包含日期、时间和时区的时间戳的字符串表示形式。将其赋值给
now_str
:
>>> now_str = '13-1-2021 15:53:39 +05:30'
- 将
now_str
转换为now
,一个datetime.datetime
对象。打印出来:
>>> now = datetime.strptime(now_str, "%d-%m-%Y %H:%M:%S %z") >>> print(now)
我们得到以下输出:
2021-01-13 15:53:39+05:30
- 确认 now 是
datetime
类型:
>>> print(type(now))
我们得到以下输出:
<class 'datetime.datetime'>
如何工作…
在步骤 1中,你从datetime
模块中导入datetime
类。在步骤 2中,你创建一个包含有效时间戳的字符串,并将其赋值给一个新属性now_str
。datetime
模块有一个strptime()
方法,可以将一个特定格式的字符串转换为datetime
对象。在步骤 3中,你将now_str
,一个格式为DD-MM-YYYY HH:MM:SS +Z
的字符串,转换为now
。在步骤 4中,你确认now
确实是datetime
类型的对象。在步骤 3中使用的指令与将 datetime 对象转换为字符串配方中描述的相同。
还有更多
当将字符串读入datetime
对象时,应使用适当的指令消耗整个字符串。部分消耗字符串将引发异常,如下面的代码片段所示。错误消息显示了未转换的数据,并可用于修复提供给strptime()
方法的指令。
尝试使用strptime()
方法将now_str
转换为datetime
对象。只传递包含字符串日期部分指令的字符串。注意错误:
>>> now = datetime.strptime(now_str, "%d-%m-%Y")
输出如下:
# Note: It's expected to have an error below --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-96-dc92a0358ed8> in <module> ----> 1 now = datetime.strptime(now_str, "%d-%m-%Y") 2 # Note: It's expected to get an error below /usr/lib/python3.8/_strptime.py in _strptime_datetime(cls, data_string, format) 566 """Return a class cls instance based on the input string and the 567 format string.""" --> 568 tt, fraction, gmtoff_fraction = _strptime(data_string, format) 569 tzname, gmtoff = tt[-2:] 570 args = tt[:6] + (fraction,) /usr/lib/python3.8/_strptime.py in _strptime(data_string, format) 350 (data_string, format)) 351 if len(data_string) != found.end(): --> 352 raise ValueError("unconverted data remains: %s" % 353 data_string[found.end():]) 354 ValueError: unconverted data remains: 15:53:39 +05:30
datetime
对象和时区
有两种类型的datetime
对象——时区无关和时区感知。时区无关对象不包含时区信息,而时区感知对象包含时区信息。这个配方演示了在datetime
对象上执行多个与时区相关的操作:创建时区无关和时区感知对象,向时区感知对象添加时区信息,从时区无关对象中删除时区信息,以及比较时区感知和时区无关对象。
如何做…
执行此配方的以下步骤:
- 从 Python 标准库中导入必要的模块:
>>> from datetime import datetime
- 创建一个时区无关的
datetime
对象。将其赋给now_tz_naive
并打印它:
>>> now_tz_unaware = datetime.now() >>> print(now_tz_unaware)
我们得到了以下输出。您的输出可能会有所不同:
2020-08-12 20:55:50.598800
- 打印
now_tz_naive
的时区信息。注意输出:
>>> print(now_tz_unaware.tzinfo)
我们得到了以下输出:
None
- 创建一个时区感知的
datetime
对象。将其赋给now_tz_aware
并打印它:
>>> now_tz_aware = datetime.now().astimezone() >>> print(now_tz_aware)
我们得到了以下输出。您的输出可能会有所不同:
2020-08-12 20:55:51.004671+05:30
- 打印
now_tz_aware
的时区信息。注意输出:
>>> print(now_tz_aware.tzinfo)
我们得到了以下输出。您的输出可能会有所不同:
IST
- 通过从
now_tz_aware
中添加时区信息创建一个新时间戳。将其赋给new_tz_aware
并打印它:
>>> new_tz_aware = now_tz_naive.replace(tzinfo=now_tz_aware.tzinfo) >>> print(new_tz_aware)
输出如下。您的输出可能会有所不同:
2020-08-12 20:55:50.598800+05:30
- 使用
tzinfo
属性打印new_tz_aware
的时区信息。注意输出:
>>> print(new_tz_aware.tzinfo)
输出如下。您的输出可能会有所不同:
IST
- 通过从
new_tz_aware
中移除时区信息创建一个新的时间戳。将其赋给new_tz_naive
并打印它:
>>> new_tz_naive = new_tz_aware.replace(tzinfo=None) >>> print(new_tz_naive)
输出如下。您的输出可能会有所不同:
2020-08-12 20:55:50.598800
- 使用
tzinfo
属性打印new_tz_naive
的时区信息。注意输出:
>>> print(new_tz_naive.tzinfo)
输出如下:
None
工作原理如下…
在 步骤 1 中,从 datetime
模块中导入 datetime
类。在 步骤 2 中,使用 now()
方法创建一个时区无关的 datetime
对象,并将其赋给一个新属性 now_tz_naive
。在 步骤 3 中,使用 tzinfo
属性打印 now_tz_naive
所持有的时区信息。观察到输出为 None
,因为这是一个时区无关的对象。
步骤 4 中,使用 now()
和 astimezone()
方法创建了一个时区感知的 datetime
对象,并将其赋给一个新属性 now_tz_aware
。步骤 5 中,使用 tzinfo
属性打印了 now_tz_aware
所持有的时区信息。注意输出为 IST
而不是 None
,因为这是一个时区感知对象。
在 步骤 6 中,通过向 now_tz_naive
添加时区信息来创建一个新的 datetime
对象。时区信息来自 now_tz_aware
。你可以使用 replace()
方法实现这一点(有关更多信息,请参阅 修改 datetime 对象 配方)。将其赋给一个新变量 new_tz_aware
。在 步骤 7 中,打印 new_tz_aware
所持有的时区信息。观察到它与 步骤 5 中的输出相同,因为你从 now_tz_aware
中取了时区信息。同样,在 步骤 8 和 步骤 9 中,你创建了一个新的 datetime
对象 new_tz_naive
,但这次你移除了时区信息。
还有更多
您只能在时区无关或时区感知的 datetime
对象之间使用比较运算符。你不能比较一个时区无关的 datetime
对象和一个时区感知的 datetime
对象。这样做会引发异常。这在以下步骤中得到了证明:
- 比较两个时区无关对象,
new_tz_naive
和now_tz_naive
。注意输出:
>>> new_tz_naive <= now_tz_naive
- 比较两个时区感知对象,
new_tz_aware
和now_tz_aware
。注意输出:
>>> new_tz_aware <= now_tz_aware
我们得到了以下输出:
True
- 比较一个时区感知对象和一个时区不感知对象,
new_tz_aware
和now_tz_naive
。注意错误:
>>> new_tz_aware > now_tz_naive
我们得到以下输出:
------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-167-a9433bb51293> in <module> ----> 1 new_tz_aware > now_tz_naive 2 # Note: It's expected to get an error below TypeError: can't compare offset-naive and offset-aware datetimes
创建一个 pandas.DataFrame 对象
现在我们已经完成了日期和时间的处理,让我们转向处理时间序列数据。pandas
库有一个pandas.DataFrame
类,对于处理和操作这样的数据很有用。这个示例从创建这些对象开始。
如何做…
对于这个示例,执行以下步骤:
- 从 Python 标准库中导入必要的模块:
>>> from datetime import datetime >>> import pandas
- 创建一个时间序列数据的示例,作为一个字典对象列表。将其分配给
time_series
数据:
>>> time_series_data = \ [{'date': datetime.datetime(2019, 11, 13, 9, 0), 'open': 71.8075, 'high': 71.845, 'low': 71.7775, 'close': 71.7925, 'volume': 219512}, {'date': datetime.datetime(2019, 11, 13, 9, 15), 'open': 71.7925, 'high': 71.8, 'low': 71.78, 'close': 71.7925, 'volume': 59252}, {'date': datetime.datetime(2019, 11, 13, 9, 30), 'open': 71.7925, 'high': 71.8125, 'low': 71.76, 'close': 71.7625, 'volume': 57187}, {'date': datetime.datetime(2019, 11, 13, 9, 45), 'open': 71.76, 'high': 71.765, 'low': 71.735, 'close': 71.7425, 'volume': 43048}, {'date': datetime.datetime(2019, 11, 13, 10, 0), 'open': 71.7425, 'high': 71.78, 'low': 71.7425, 'close': 71.7775, 'volume': 45863}, {'date': datetime.datetime(2019, 11, 13, 10, 15), 'open': 71.775, 'high': 71.8225, 'low': 71.77, 'close': 71.815, 'volume': 42460}, {'date': datetime.datetime(2019, 11, 13, 10, 30), 'open': 71.815, 'high': 71.83, 'low': 71.7775, 'close': 71.78, 'volume': 62403}, {'date': datetime.datetime(2019, 11, 13, 10, 45), 'open': 71.775, 'high': 71.7875, 'low': 71.7475, 'close': 71.7525, 'volume': 34090}, {'date': datetime.datetime(2019, 11, 13, 11, 0), 'open': 71.7525, 'high': 71.7825, 'low': 71.7475, 'close': 71.7625, 'volume': 39320}, {'date': datetime.datetime(2019, 11, 13, 11, 15), 'open': 71.7625, 'high': 71.7925, 'low': 71.76, 'close': 71.7875, 'volume': 20190}]
- 从
time_series_data
创建一个新的DataFrame
。将其分配给df
并打印它:
>>> df = pandas.DataFrame(time_series_data)
我们得到以下输出:
date open high low close volume 0 2019-11-13 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 1 2019-11-13 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 2 2019-11-13 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 3 2019-11-13 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 4 2019-11-13 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 5 2019-11-13 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 6 2019-11-13 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 7 2019-11-13 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 8 2019-11-13 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 9 2019-11-13 11:15:00 71.7625 71.7925 71.7600 71.7875 20190
- 获取
df
中的列列表:
>>> df.columns.tolist()
我们得到以下输出:
['date', 'open', 'high', 'low', 'close', 'volume']
- 再次使用
time_series_data
创建一个DataFrame
对象。这次,按照你想要的顺序指定列:
>>> pandas.DataFrame(time_series_data, columns=['close','date', 'open', 'high', 'low', 'volume'])
我们得到以下输出:
close date open high low volume 0 71.7925 2019-11-13 09:00:00 71.8075 71.8450 71.7775 219512 1 71.7925 2019-11-13 09:15:00 71.7925 71.8000 71.7800 59252 2 71.7625 2019-11-13 09:30:00 71.7925 71.8125 71.7600 57187 3 71.7425 2019-11-13 09:45:00 71.7600 71.7650 71.7350 43048 4 71.7775 2019-11-13 10:00:00 71.7425 71.7800 71.7425 45863 5 71.8150 2019-11-13 10:15:00 71.7750 71.8225 71.7700 42460 6 71.7800 2019-11-13 10:30:00 71.8150 71.8300 71.7775 62403 7 71.7525 2019-11-13 10:45:00 71.7750 71.7875 71.7475 34090 8 71.7625 2019-11-13 11:00:00 71.7525 71.7825 71.7475 39320 9 71.7875 2019-11-13 11:15:00 71.7625 71.7925 71.7600 20190
Python 算法交易秘籍(一)(3)https://developer.aliyun.com/article/1523085