【问题标题】:Object oriented design for an investment/stock and options portfolio in PythonPython中投资/股票和期权组合的面向对象设计
【发布时间】:2011-03-23 01:26:21
【问题描述】:

我是一名初级/中级 Python 程序员,但我还没有编写应用程序,只是编写了脚本。我目前没有使用很多面向对象的设计,所以我希望这个项目能够帮助我培养我的 OOD 技能。问题是,我不知道从设计角度从哪里开始(我知道如何创建对象和所有这些东西)。不管怎样,我也是自学成才,没有接受过正规的 CS 教育。

我想尝试编写一个程序来跟踪投资组合中的股票/期权头寸。

我大致了解什么是好的候选对象(投资组合、股票、期权等)和方法(购买、销售、UpdateData 等)。

多头头寸有买入开仓和卖出平仓,而空头头寸有卖出开仓和买入平仓。

portfolio.PlaceOrder(type="BUY", symbol="ABC", date="01/02/2009", price=50.00, qty=100)
portfolio.PlaceOrder(type="SELL", symbol="ABC", date="12/31/2009", price=100.00, qty=25)
portfolio.PlaceOrder(type="SELLSHORT", symbol="XYZ", date="1/2/2009", price=30.00, qty=50)
portfolio.PlaceOrder(type="BUY", symbol="XYZ", date="2/1/2009", price=10.00, qty=50)

那么,一旦调用了这个方法,我该如何存储信息呢?起初我以为我会有一个带有 Symbol、OpenDate、OpenPrice 等属性的 Position 对象,但考虑更新仓位以考虑销售变得很棘手,因为买卖发生在不同的时间和金额。

  • 买入100股开盘,1次,1价。销售 4 个不同的时间,4 个不同的价格。
  • 购买 100 股。每天卖出 1 股,持续 100 天。
  • 购买4个不同的时间,4个不同的价格。以 1 次、1 个价格卖出全部仓位。

一种可能的解决方案是为每一股股票创建一个对象,这样每一股就会有不同的日期和价格。这会不会有太多开销?投资组合可能有成千上万个小 Share 对象。如果您想了解某个头寸的总市值,您需要以下内容:

sum([trade.last_price for trade in portfolio.positions if trade.symbol == "ABC"])

如果你有一个位置对象,计算会很简单:

position.last * position.qty

提前感谢您的帮助。查看其他帖子,很明显 SO 是“帮助”而不是“为您编写程序”。我觉得我只需要一些方向,指明正确的道路。

反思后的附加信息 目的 该程序将跟踪所有未平仓头寸;能够查看详细的损益。

当我想到详细的损益表时,我想查看... - 所有开放日期(和关闭日期) - 举行时间 - 开盘价(收盘日期) - 自开盘以来的损益 - 每天的损益

@Senderle

我想也许你对“对象”的比喻过于字面化了,因此正试图将在某些方面看起来非常像对象的共享变成编程意义上的对象。如果是这样,那是一个错误,这就是我认为并列的观点。

这是我的错误。考虑share 对象的“对象”似乎很自然。直到可能有数百万人,这个想法才显得疯狂。这个周末我会有一些空闲的编码时间,并会尝试创建一个有数量的对象。

【问题讨论】:

  • 您需要一个用于此类应用的数据库层。
  • 出于好奇,对这个术语不太熟悉,“未平仓”头寸只是持有特定股票的非零(对空头头寸为正或负),我说得对吗?
  • 是的,未平仓头寸将是非零的。基本上有两种类型的头寸:多头和空头。做多是大多数人在投​​资时想到的。低买高卖。空头头寸与做多相反。你从你的经纪人那里借入股票并在市场上出售,产生了一种责任,你必须将股票归还给你坏掉的股票(或者当他要求退还股票时)。过程是(借入股票)高卖低买(将它们归还给您的经纪人)。
  • 我知道这篇文章已经很老了,但我很想知道你是否在这里取得了任何进展,因为我正在考虑同样的问题,而你距离我还有 2 年的时间。

标签: python projects-and-solutions stocks trading


【解决方案1】:

在设计这样的系统时,您应该牢记两个基本原则:

  1. 消除数据中的冗余。没有冗余可以确保完整性。
  2. 将回答任何查询所需的所有数据保持在最低的详细程度。

基于这些规则,我的建议是维护一个事务日志文件。每笔交易都代表某种状态的变化,以及有关它的所有相关事实:何时、什么、买/卖、多少、多少等。每笔交易都将由一条记录表示(命名元组在这里很有用)在一个平面文件中。一年(甚至 5 或 10 年)的交易应该很容易放入内存驻留列表中。然后,您可以创建函数来从该列表中选择、排序和汇总您需要的任何信息,并且它驻留在内存中,速度将惊人地快,比 SQL 数据库快得多。

当交易日志变得太大或太慢时,您可以计算您在特定日期(如年末)的所有头寸状态,将其用作下一个时期的初始状态,并存档您的旧日志文件到光盘。

您可能需要一些关于您所持资产的辅助信息,例如任何特定日期的价值/价格,以便您可以绘制任何或所有资产的价值与时间的关系(此类信息有在线资源,雅虎财经一个。)包含有关您的每个馆藏的静态信息的主数据库也很有用。

我知道这听起来不太“面向对象”,但是 OO 设计可能有助于将系统的详细工作隐藏在 TransLog 对象中,并使用方法将数据保存到磁盘/从磁盘恢复数据(保存/open 方法),输入/更改/删除事务;以及将数据处理成有意义的信息显示的其他方法。

首先使用命令行界面编写 API。当这令您满意时,如果您愿意,您可以继续创建 GUI 前端。

祝你好运,玩得开心!

【讨论】:

    【解决方案2】:

    避开物体。面向对象的设计是有缺陷的。将您的程序视为对数据(列表和字典)进行操作的行为的集合。然后将您的相关行为分组为模块中的函数。 每个功能都应该有明确的输入和输出。在每个模块中全局存储您的数据。 为什么没有对象?因为它更接近问题空间。面向对象的编程创建了太多的间接性来解决问题。不必要的间接导致软件膨胀和错误。

    一种可能的解决方案是为每一股股票创建一个对象,这样每一股就会有不同的日期和价格。这会不会有太多开销?投资组合可能有成千上万个小 Share 对象。如果您想了解某个头寸的总市值,您需要以下信息:

    是的,开销太大了。这里的解决方案是将数据存储在数据库中。除非您使用 NOSQL 方案,否则查找头寸的总市值将在 SQL 中完成。

    不要试图针对所有可能的未来结果进行设计。只需让您的程序按照它现在需要的方式运行即可。

    【讨论】:

    • 我同意“将您的数据存储在数据库中”和“不要过度设计一切”;我完全不同意“面向对象的设计有缺陷”。有可能做得不好,但任何事情都是如此。
    • 也许我不知道怎么做才对。但我喜欢做东西。不要考虑制作它们。
    • @juxtapose:真的吗?你不假思索地做了多少个超过 500 行的程序?
    • @Hugh Heh。这不是我的意思。我在 OO 方面的经验是,我必须经历很多困难才能解决问题。此外,程序往往更复杂,因为我添加了不必要的抽象。具有一组功能的模块总是可以完成这项工作。也许我还没有开发过真正庞大而复杂的软件......但我不确定我是否也想要。
    • 我非常同意休的评论。 @juxtapose:我喜欢让“问题空间”确定解决方案的想法,并且一组函数可能是 OOD 解决方案的替代方案。
    【解决方案3】:

    我想我会把它分成

    • 持有量(您当前拥有或欠每个符号的资产)
    • 订单(一次购买或出售单个符号的简单要求)
    • 交易(订单集合)

    这使得获取当前值、排队订单和构建更复杂的订单以及轻松映射到数据对象(其背后有数据库)变得非常容易。

    【讨论】:

    • 我试图想象这将如何工作。很明显,价格历史应该存储在数据库中。但是股票呢?我还想使用一个对象作为共享的想法吗? (仅在这种情况下,它将是数据库记录而不是对象)
    【解决方案4】:

    回答您的问题:您似乎已经对自己的数据模型有了相当清晰的了解。但在我看来,您需要更多地考虑您希望该程序做什么。它会跟踪股票价格的变化吗?下订单,或建议下订单?或者它会简单地跟踪您下的订单吗?这些用途中的每一种都可能需要不同的策略。

    也就是说,我不明白为什么您需要为每个共享拥有一个对象;我不明白该策略背后的原因。即使您希望能够非常详细地跟踪您的订单历史记录,您也可以只存储汇总数据,例如“x 股票在y 美元/股,日期为z”。

    拥有一个position 对象(或holding 对象,用 Hugh 的术语)会更有意义——如果您真的需要详细的持股历史,每只股票一个,也许带有 .order_history 属性在那个股票。是的,数据库肯定对这类事情有用。

    暂时哲学化一下:我想也许你把“对象”这个比喻太从字面上理解了,所以试图分享一下,这在某些方面看起来很像对象, 变成编程意义上的对象。如果是这样,那是一个错误,这就是我认为并列的观点。

    我不同意他的观点,即面向对象的设计存在缺陷——这是一个相当大胆的声明! - 但他的回答是正确的,因为“对象”(又名类实例)几乎与模块相同**。它是链接到某些共享状态的相关函数的集合。在类实例中,状态通过selfthis 共享,而在模块中,状态通过全局命名空间共享。

    在大多数情况下,类实例和模块之间的唯一主要区别是可以有许多类实例,每个类实例都有自己独立的状态,而模块实例只能有一个。 (当然还有其他区别,但大多数时候它们涉及对学习 OOD 不是很重要的技术问题。)这意味着您可以以类似于您考虑模块的方式来考虑对象,并且这是一个有用的方法。

    **在许多编译语言中,编译模块时生成的文件称为“对象”文件。我认为这就是“对象”隐喻的真正来源。 (我没有任何真正的证据!所以任何更了解的人,请随时纠正我。)人们看到的无处不在的 OOD 玩具示例 -- car.drive(mph=50); car.stop(); car.refuel(unleaded, regular) -- 我相信是可以混淆的反向格式有点概念。

    【讨论】:

    • 谢谢,您的评论很有帮助。我同意从字面上考虑这个问题。
    【解决方案5】:

    我很想听听您的想法。我大约需要 4 个月(兼职)来创建一个订单处理程序,虽然它大部分完成了,但我仍然有和你一样的问题,因为我希望它能够正确地完成。

    目前,我保存了两个文件

    一个“策略命中日志”,其中保存了来自任何策略脚本的每个买入/​​卖出信号。例如:当buy_at_yesterdays_close_price.py 策略被触发时,它将购买请求保存在这个文件中,并将请求传递给Order Handler

    一个“Order Log”,它是一个单独的 DataFrame - 此文件符合您关注的目的。

    • 来自策略的每个请求都与单个基础证券(例如,AAPL 股票)相关,并创建一个 Order,该订单在 DataFrame 中保存为一行,其中包含 Ticker、Strategy 的列产生此 Order 以及 SuborderBroker Suborder 列的名称(如下所述)。
    • 每个订单都有一个存储在“子订单”列中的子订单(字典)列表。例如:如果您看好 AAPL,子订单可能是:
    [
    {'security': 'equity', 'quantity':10},
    {'security': 'option call', 'quantity':10}
    ]
    
    • 每个订单还有一个存储在 Broker Suborder 列中的 Broker Suborders (dicts) 列表。每个经纪人子订单都是对经纪人的买入或卖出证券的请求,并使用经纪人为该请求提供的“订单 ID”进行索引。对经纪人的每个新请求都是一个新的经纪人子订单,取消该经纪人子订单记录在该字典中。要记录对经纪人子定单的修改,您取消旧的经纪人子定单并发送并记录一个新的(使用 IBKR 的佣金相同)。

    改进

    1. 类列表而不是 DataFrame:我认为将每个 Order 保存为 Order_Class 的实例(而不是 DataFrame 的一行)会更加pythonic,它具有SuborderBroker_Suborder 属性,它们也是 Suborder_ClassBroker_Suborder_Class 的实例。 我目前的问题是保存一个类列表作为我所有打开和关闭订单的记录是pythonic还是愚蠢。

    2. 可视化注意事项:看起来订单应该以表格形式保存以便于查看,但也许最好将它们保存在这种“类实例列表”形式中并使用函数来表格化他们在观看时?任何人的任何输入将不胜感激。我想摆脱这个并开始使用 ML,但我不想让 Order Handler 未完成。

    3. 都是废话吗?:每个Broker Suborder(对经纪人的买卖请求)是否应该附加到Order(这只是来自策略脚本的特定策略请求)还是应该按时间顺序记录所有Broker Suborders,并简单地引用产生Broker Suborder 的策略顺序(Order)? Idk...但我希望大家的意见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-03
      • 2018-03-25
      • 2020-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多