Python 金融编程第二版(GPT 重译)(三)(2)

简介: Python 金融编程第二版(GPT 重译)(三)

Python 金融编程第二版(GPT 重译)(三)(1)https://developer.aliyun.com/article/1559326


Python 类的基础知识

本节涉及主要概念和具体语法,以利用 Python 中的 OOP。当前的背景是构建自定义类来模拟无法轻松、高效或适当地由现有 Python 对象类型建模的对象类型。在金融工具的示例中,只需两行代码即可创建一个新的 Python 类。

In [44]: class FinancialInstrument(object):  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             pass  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
In [45]: fi = FinancialInstrument()  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
In [46]: type(fi)  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
Out[46]: __main__.FinancialInstrument
In [47]: fi  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
Out[47]: <__main__.FinancialInstrument at 0x10a21c828>
In [48]: fi.__str__()  ![5](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/5.png)
Out[48]: '<__main__.FinancialInstrument object at 0x10a21c828>'
In [49]: fi.price = 100  ![6](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/6.png)
In [50]: fi.price  ![6](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/6.png)
Out[50]: 100


类定义语句。²


一些代码;这里只是pass关键字。


一个名为fi的类的新实例。


每个 Python 对象都带有某些特殊属性和方法(来自object);这里调用了用于检索字符串表示的特殊方法。


所谓的数据属性 —— 与常规属性相对 —— 可以为每个对象即时定义。


一个重要的特殊方法是__init__,它在每次实例化对象时被调用。它以对象自身(按照惯例为self)和可能的多个其他参数作为参数。除了实例属性之外

In [51]: class FinancialInstrument(object):
             author = 'Yves Hilpisch'  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             def __init__(self, symbol, price):  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
                 self.symbol = symbol  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
                 self.price = price  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
In [52]: FinancialInstrument.author  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
Out[52]: 'Yves Hilpisch'
In [53]: aapl = FinancialInstrument('AAPL', 100)  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
In [54]: aapl.symbol  ![5](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/5.png)
Out[54]: 'AAPL'
In [55]: aapl.author  ![6](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/6.png)
Out[55]: 'Yves Hilpisch'
In [56]: aapl.price = 105  ![7](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/7.png)
In [57]: aapl.price  ![7](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/7.png)
Out[57]: 105


类属性的定义(=每个实例都继承的)。


在初始化期间调用特殊方法__init__


实例属性的定义(=每个实例都是个别的)。


一个名为fi的类的新实例。


访问实例属性。


访问类属性。


更改实例属性的值。

金融工具的价格经常变动,金融工具的符号可能不会变动。为了向类定义引入封装,可以定义两个方法get_price()set_price()。接下来的代码还额外继承了之前的类定义(不再继承自object)。

In [58]: class FinancialInstrument(FinancialInstrument):  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             def get_price(self):  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
                 return self.price  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
             def set_price(self, price):  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
                 self.price = price  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
In [59]: fi = FinancialInstrument('AAPL', 100)  ![5](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/5.png)
In [60]: fi.get_price()  ![6](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/6.png)
Out[60]: 100
In [61]: fi.set_price(105)  ![7](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/7.png)
In [62]: fi.get_price()  ![6](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/6.png)
Out[62]: 105
In [63]: fi.price  ![8](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/8.png)
Out[63]: 105


通过从上一个版本继承的方式进行类定义。


定义get_price方法。


定义set_price方法……


……并根据参数值更新实例属性值。


基于新的类定义创建一个名为fi的新实例。


调用get_price()方法来读取实例属性值。


通过set_price()更新实例属性值。


直接访问实例属性。

封装通常的目标是隐藏用户对类的操作中的数据。添加相应的方法,有时称为gettersetter方法,是实现此目标的一部分。然而,这并不阻止用户直接访问和操作实例属性。这就是私有实例属性发挥作用的地方。它们由两个前导下划线定义。

In [64]: class FinancialInstrument(object):
             def __init__(self, symbol, price):
                 self.symbol = symbol
                 self.__price = price  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             def get_price(self):
                 return self.__price
             def set_price(self, price):
                 self.__price = price
In [65]: fi = FinancialInstrument('AAPL', 100)
In [66]: fi.get_price()  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
Out[66]: 100
In [67]: fi.__price  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
         ----------------------------------------
         AttributeErrorTraceback (most recent call last)
         <ipython-input-67-74c0dc05c9ae> in <module>()
----> 1 fi.__price  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
         AttributeError: 'FinancialInstrument' object has no attribute '__price'
In [68]: fi._FinancialInstrument__price  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
Out[68]: 100
In [69]: fi._FinancialInstrument__price = 105  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
In [70]: fi.set_price(100)  ![5](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/5.png)


价格被定义为私有实例属性。


方法get_price()返回其值。


尝试直接访问属性会引发错误。


通过在类名前添加单个下划线,仍然可以直接访问和操作。


将价格恢复到其原始值。

注意

尽管封装基本上可以通过私有实例属性和处理它们的方法来实现 Python 类,但无法完全强制隐藏数据不让用户访问。从这个意义上说,这更像是 Python 中的一种工程原则,而不是 Python 类的技术特性。

考虑另一个模拟金融工具投资组合头寸的类。通过两个类,聚合的概念很容易说明。PortfolioPosition类的一个实例将FinancialInstrument类的一个实例作为属性值。添加一个实例属性,比如position_size,然后可以计算出例如头寸价值。

In [71]: class PortfolioPosition(object):
             def __init__(self, financial_instrument, position_size):
                 self.position = financial_instrument  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
                 self.__position_size = position_size  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
             def get_position_size(self):
                 return self.__position_size
             def update_position_size(self, position_size):
                 self.__position_size = position_size
             def get_position_value(self):
                 return self.__position_size * \
                        self.position.get_price()  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
In [72]: pp = PortfolioPosition(fi, 10)
In [73]: pp.get_position_size()
Out[73]: 10
In [74]: pp.get_position_value()  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
Out[74]: 1000
In [75]: pp.position.get_price()  ![4](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/4.png)
Out[75]: 100
In [76]: pp.position.set_price(105)  ![5](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/5.png)
In [77]: pp.get_position_value()  ![6](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/6.png)
Out[77]: 1050


基于FinancialInstrument类的实例的实例属性。


PortfolioPosition类的私有实例属性。


根据属性计算位置值。


附加到实例属性对象的方法可以直接访问(也可能被隐藏)。


更新金融工具的价格。


根据更新后的价格计算新位置值。

Python 数据模型

前一节的示例已经突出了所谓的 Python 数据或对象模型的一些方面(参见https://docs.python.org/3/reference/datamodel.html)。Python 数据模型允许设计与 Python 基本语言构造一致交互的类。除其他外,它支持(参见 Ramalho(2015),第 4 页)以下任务和结构:

  • 迭代
  • 集合处理
  • 属性访问
  • 运算符重载
  • 函数和方法调用
  • 对象创建和销毁
  • 字符串表示(例如,用于打印)
  • 受管理的上下文(即with块)。

由于 Python 数据模型非常重要,本节专门介绍了一个示例,探讨了其中的几个方面。示例可在 Ramalho(2015)的书中找到,并进行了微调。它实现了一个一维,三元素向量的类(想象一下欧几里德空间中的向量)。首先,特殊方法__init__

In [78]: class Vector(object):
             def __init__(self, x=0, y=0, z=0):  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
                 self.x = x  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
                 self.y = y  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
                 self.z = z  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
In [79]: v = Vector(1, 2, 3)  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
In [80]: v  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
Out[80]: <__main__.Vector at 0x10a245d68>


三个预初始化的实例属性(想象成三维空间)。


名为v的类的新实例。


默认字符串表示。

特殊方法__str__允许定义自定义字符串表示。

In [81]: class Vector(Vector):
             def __repr__(self):
                 return 'Vector(%r, %r, %r)' % (self.x, self.y, self.z)
In [82]: v = Vector(1, 2, 3)
In [83]: v  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
Out[83]: Vector(1, 2, 3)
In [84]: print(v)  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
         Vector(1, 2, 3)


新的字符串表示。

abs()bool()是两个标准的 Python 函数,它们在Vector类上的行为可以通过特殊方法__abs____bool__来定义。

In [85]: class Vector(Vector):
             def __abs__(self):
                 return (self.x ** 2 +  self.y ** 2 +
                         self.z ** 2) ** 0.5  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             def __bool__(self):
                 return bool(abs(self))
In [86]: v = Vector(1, 2, -1)  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
In [87]: abs(v)
Out[87]: 2.449489742783178
In [88]: bool(v)
Out[88]: True
In [89]: v = Vector()  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
In [90]: v  ![3](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/3.png)
Out[90]: Vector(0, 0, 0)
In [91]: abs(v)
Out[91]: 0.0
In [92]: bool(v)
Out[92]: False


返回给定三个属性值的欧几里德范数。


具有非零属性值的新Vector对象。


仅具有零属性值的新Vector对象。

如多次显示的那样,+*运算符几乎可以应用于任何 Python 对象。其行为是通过特殊方法__add____mul__定义的。

In [93]: class Vector(Vector):
             def __add__(self, other):
                 x = self.x + other.x
                 y = self.y + other.y
                 z = self.z + other.z
                 return Vector(x, y, z)  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             def __mul__(self, scalar):
                 return Vector(self.x * scalar,
                               self.y * scalar,
                               self.z * scalar)  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
In [94]: v = Vector(1, 2, 3)
In [95]: v + Vector(2, 3, 4)
Out[95]: Vector(3, 5, 7)
In [96]: v * 2
Out[96]: Vector(2, 4, 6)


在这种情况下,两个特殊方法都返回自己的类型对象。

另一个标准的 Python 函数是 len(),它给出对象的长度,即元素的数量。当在对象上调用时,此函数访问特殊方法 __len__。另一方面,特殊方法 __getitem__ 使通过方括号表示法进行索引成为可能。

In [97]: class Vector(Vector):
             def __len__(self):
                 return 3  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
             def __getitem__(self, i):
                 if i in [0, -3]: return self.x
                 elif i in [1, -2]: return self.y
                 elif i in [2, -1]: return self.z
                 else: raise IndexError('Index out of range.')
In [98]: v = Vector(1, 2, 3)
In [99]: len(v)
Out[99]: 3
In [100]: v[0]
Out[100]: 1
In [101]: v[-2]
Out[101]: 2
In [102]: v[3]
          ----------------------------------------
          IndexErrorTraceback (most recent call last)
          <ipython-input-102-0f5531c4b93d> in <module>()
----> 1 v[3]
          <ipython-input-97-eef2cdc22510> in __getitem__(self, i)
      7         elif i in [1, -2]: return self.y
      8         elif i in [2, -1]: return self.z
----> 9         else: raise IndexError('Index out of range.')
          IndexError: Index out of range.


Vector 类的所有实例都有长度为三。

最后,特殊方法 __iter__ 定义了对对象元素进行迭代的行为。定义了此操作的对象称为可迭代的。例如,所有集合和容器都是可迭代的。

In [103]: class Vector(Vector):
              def __iter__(self):
                  for i in range(len(self)):
                      yield self[i]
In [104]: v = Vector(1, 2, 3)
In [105]: for i in range(3):  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
              print(v[i])  ![1](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/1.png)
          1
          2
          3
In [106]: for coordinate in v:  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
              print(coordinate)  ![2](https://gitee.com/OpenDocCN/ibooker-quant-zh/raw/master/docs/py-fin-2e/img/2.png)
          1
          2
          3


使用索引值进行间接迭代(通过__getitem__)。


对类实例进行直接迭代(使用__iter__)。

提示

Python 数据模型允许定义与标准 Python 操作符、函数等无缝交互的 Python 类。这使得 Python 成为一种相当灵活的编程语言,可以轻松地通过新类和对象类型进行增强。

总之,子节 “向量类” 在单个代码块中提供了 Vector 类的定义。

结论

本章从理论上和基于 Python 示例介绍了面向对象编程(OOP)的概念和方法。OOP 是 Python  中使用的主要编程范式之一。它不仅允许建模和实现相当复杂的应用程序,还允许创建自定义对象,这些对象由于灵活的 Python 数据模型,与标准  Python 对象表现得相似。尽管有许多批评者反对 OOP,但可以肯定地说,当达到一定复杂程度时,它为 Python  程序员和量化人员提供了强大的手段和工具。在 [Link to Come] 中讨论和展示的衍生定价包呈现了这样一个情况,其中 OOP  似乎是唯一合理的编程范式,以处理固有的复杂性和对抽象的需求。


Python 金融编程第二版(GPT 重译)(三)(3)https://developer.aliyun.com/article/1559335

相关文章
|
4天前
|
数据挖掘 索引 Python
Python数据挖掘编程基础3
字典在数学上是一个映射,类似列表但使用自定义键而非数字索引,键在整个字典中必须唯一。可以通过直接赋值、`dict`函数或`dict.fromkeys`创建字典,并通过键访问元素。集合是一种不重复且无序的数据结构,可通过花括号或`set`函数创建,支持并集、交集、差集和对称差集等运算。
14 9
|
3天前
|
存储 开发者 Python
探索Python编程的奥秘
【9月更文挑战第29天】本文将带你走进Python的世界,通过深入浅出的方式,解析Python编程的基本概念和核心特性。我们将一起探讨变量、数据类型、控制结构、函数等基础知识,并通过实际代码示例,让你更好地理解和掌握Python编程。无论你是编程新手,还是有一定基础的开发者,都能在这篇文章中找到新的启示和收获。让我们一起探索Python编程的奥秘,开启编程之旅吧!
|
4天前
|
算法 Python
Python编程的函数—内置函数
Python编程的函数—内置函数
|
4天前
|
存储 索引 Python
Python编程的常用数据结构—列表
Python编程的常用数据结构—列表
|
4天前
|
数据挖掘 Python
Python数据挖掘编程基础8
在Python中,默认环境下并不会加载所有功能,需要手动导入库以增强功能。Python内置了诸多强大库,例如`math`库可用于复杂数学运算。导入库不仅限于`import 库名`,还可以通过别名简化调用,如`import math as m`;也可指定导入库中的特定函数,如`from math import exp as e`;甚至直接导入库中所有函数`from math import *`。但需注意,后者可能引发命名冲突。读者可通过`help(&#39;modules&#39;)`查看已安装模块。
9 0
|
4天前
|
人工智能 数据挖掘 Serverless
Python数据挖掘编程基础
函数式编程中的`reduce`函数用于对可迭代对象中的元素进行累积计算,不同于逐一遍历的`map`函数。例如,在Python3中,计算n的阶乘可以使用`reduce`(需从`funtools`库导入)实现,也可用循环命令完成。另一方面,`filter`函数则像一个过滤器,用于筛选列表中符合条件的元素,同样地功能也可以通过列表解析来实现。使用这些函数不仅使代码更加简洁,而且由于其内部循环机制,执行效率通常高于普通的`for`或`while`循环。
9 0
|
4天前
|
分布式计算 数据挖掘 Serverless
Python数据挖掘编程基础6
函数式编程(Functional Programming)是一种编程范型,它将计算机运算视为数学函数计算,避免程序状态及易变对象的影响。在Python中,函数式编程主要通过`lambda`、`map`、`reduce`、`filter`等函数实现。例如,对于列表`a=[5,6,7]`,可通过列表解析`b=[i+3 for i in a]`或`map`函数`b=map(lambda x:x+3, a)`实现元素加3的操作,两者输出均为`[8,9,10]`。尽管列表解析代码简洁,但其本质仍是for循环,在Python中效率较低;而`map`函数不仅功能相同,且执行效率更高。
6 0
|
4天前
|
数据挖掘 Python
Python数据挖掘编程基础5
函数是Python中用于提高代码效率和减少冗余的基本数据结构,通过封装程序逻辑实现结构化编程。用户可通过自定义或函数式编程方式设计函数。在Python中,使用`def`关键字定义函数,如`def pea(x): return x+1`,且其返回值形式多样,可为列表或多个值。此外,Python还支持使用`lambda`定义简洁的行内函数,例如`c=lambda x:x+1`。
9 0
|
4天前
|
数据挖掘 Python
Python数据挖掘编程基础
判断与循环是编程的基础,Python中的`if`、`elif`、`else`结构通过条件句来执行不同的代码块,不使用花括号,依赖缩进区分代码层次。错误缩进会导致程序出错。Python支持`for`和`while`循环,`for`循环结合`range`生成序列,简洁直观。正确缩进不仅是Python的要求,也是一种良好的编程习惯。
11 0
|
4天前
|
人工智能 小程序 API
ChatTTS+Python编程实现语音报时小程序
ChatTTS+Python编程实现语音报时小程序
13 0
下一篇
无影云桌面