【问题标题】:Sell Stock Loop from multiple portfolios从多个投资组合中卖出股票循环
【发布时间】:2017-05-02 14:23:16
【问题描述】:

所以我在 R 中有 2 个数据框。一个是需要出售的股票和数量的表格 (SSTable),第二个是股票位于不同投资组合中的表格 (PTable)。除了 PTable 中的投资组合、库存和数量字段外,还有一个日期字段。 Ptable 需要从最早日期到最晚日期进行排序。

我需要构建某种类型的脚本来循环遍历 SSTable 和 PTable,并告诉我要从每个投资组合中卖出哪些股票以及卖出多少。我应该在它的末尾有 2 个输出表。

SSTableOP- 此表应仅包含无法出售的剩余份额。

PTableOP - 此表是我的执行表,指示要从哪个投资组合中以哪个顺序出售哪些股票。希望按投资组合然后股票名称对其进行排序。请注意,我的销售额不能超过我在任何投资组合中的总和。举个例子,如果我的 SSTable 表明我需要卖出 400 个 AAPL,但在我所有的投资组合中我只有 200 个,那么它应该告诉我只卖出我拥有的 200 个。现在 SSTableOP 中应该没有 AAPL 的记录。一个重要的注意事项是,我必须首先出售具有最近日期的投资组合中的单位。那是我必须卖出的顺序

我的所有组合投资组合中的销售额都不能超过我的销售额

这是一些示例数据以及我的数据框的结构

结构 SSTable

 Classes ‘tbl_df’, ‘tbl’ and 'data.frame':  58 obs. of  2 variables:
$ ticker          : chr  
$ Units           : int  

结构 PTable

  Classes ‘grouped_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':   1030 obs. of  4 
  variables:
    $ Portfolio                : Factor w/ 2665 levels ".
    $ ticker                   : Factor w/ 4677 levels .
    $ Units                    : int  
    $ Date                     : POSIXct, format: 

SSTable - 数据

ticker  Units
APPL     400
GOOG     1700
MFC      800
PWF      200
GWG      500
SUN      600
ARIA    200
HEI     100
GEO     300

PTable 数据

Portfolio   ticker  units   date
HGFR 6/17   APPL    200    20/04/2017
HGFR 6/17   GOOG    800    20/04/2017
HGFR 6/17   MFC     200    20/04/2017
SDSDF14     SUN     600    22/04/2017
DFDS11      GOOG    1700   25/04/2017
DFDS11      ARIA    100    25/04/2017
SDSDF14     ARIA    100    22/04/2017
SDSDF14     GEO     50     22/04/2017
SDSDF14     HEI     50     22/04/2017
HGFR 6/17   GWG     250    20/04/2017
GDSD114     HEI     50     26/04/2017
GDSD114    GEO      150    26/04/2017
GDSD114    PWF      50     26/04/2017

PTableOP

SSTableOP

ticker  Units
APPL    200
MFC     600
PWF     150
GWG     250
GEO     100

【问题讨论】:

    标签: r loops dplyr


    【解决方案1】:

    投资组合名称 HGFR 6/17 稍作修改,便于作为表格阅读

    PTable <- read.table(header=TRUE, stringsAsFactors = FALSE, text= 
    "Portfolio   ticker  units   pdate
    HGFR_6/17   APPL    200    20/04/2017
    HGFR_6/17   GOOG    800    20/04/2017
    HGFR_6/17   MFC     200    20/04/2017
    SDSDF14     SUN     600    22/04/2017
    DFDS11      GOOG    1700   25/04/2017
    DFDS11      ARIA    100    25/04/2017
    SDSDF14     ARIA    100    22/04/2017
    SDSDF14     GEO     50     22/04/2017
    SDSDF14     HEI     50     22/04/2017
    HGFR_6/17   GWG     250    20/04/2017
    GDSD114     HEI     50     26/04/2017
    GDSD114    GEO      150    26/04/2017
    GDSD114    PWF      50     26/04/2017
    ")
    
    SSTable <- read.table(header=TRUE, stringsAsFactors = FALSE, text= 
    "ticker  Units
    APPL     400
    GOOG     1700
    MFC      800
    PWF      200
    GWG      500
    SUN      600
    ARIA    200
    HEI     100
    GEO     300
    ")
    
    library(dplyr)
    library(lubridate)
    
    # ensure a date type (date renamed to pdate)
    PTable$pdate <- dmy(PTable$pdate)
    
    # First determine actual amount that can be sold based on 
    # overall portfolio balances. This may not be strictly
    # needed but it simplifies later logic. left join in
    # case there are sell orders without any mathcing portfolios
    
    SSTableAdjusted <- SSTable %>%
      left_join(PTable %>% group_by(ticker) %>% summarize(per_ticker_portfolio_units = sum(units))) %>%
      mutate(
        per_ticker_sell_units = if_else(Units > per_ticker_portfolio_units, per_ticker_portfolio_units, Units),
        per_ticker_unfulfilled_units = Units - per_ticker_sell_units) %>%
      arrange(ticker)
    
    # process
    
    PTableSummary <- PTable %>%
      # join in the per ticker targets
      left_join(SSTableAdjusted) %>%
      # arrange in date priority
      arrange(pdate, Portfolio) %>% 
      # group by ticker to compare totals by ticker
      group_by(ticker) %>%
      # apply the trading logic
      mutate(
        cum_portfolio_units = cumsum(lag(units, default = 0)),
        gap = per_ticker_sell_units - cum_portfolio_units,
        to_sell = if_else(gap <= 0, 0L, 
                     if_else(gap >= units, units,
                     gap)),
        remaining_to_sell = Units - cumsum(to_sell)) %>%
      ungroup() %>%
      arrange(pdate, Portfolio, ticker) 
    
    # test conditions - all should be TRUE
    sum(PTableSummary$to_sell) == sum(SSTableAdjusted$per_ticker_sell_units)
    PTableSummary$to_sell <= PTableSummary$units
    
    
    # make the output table (doenseparately so that PTAbleSummary can be inspected)
    PTableOP <- PTableSummary %>%
      select(pdate, Portfolio, ticker, units, to_sell,  remaining_to_sell)  %>%
      arrange(pdate, Portfolio, ticker)
    
    #         pdate Portfolio ticker units to_sell remaining_to_sell
    # 1  2017-04-20 HGFR_6/17   APPL   200     200               200
    # 2  2017-04-20 HGFR_6/17   GOOG   800     800               900
    # 3  2017-04-20 HGFR_6/17    GWG   250     250               250
    # 4  2017-04-20 HGFR_6/17    MFC   200     200               600
    # 5  2017-04-22   SDSDF14   ARIA   100     100               100
    # 6  2017-04-22   SDSDF14    GEO    50      50               250
    # 7  2017-04-22   SDSDF14    HEI    50      50                50
    # 8  2017-04-22   SDSDF14    SUN   600     600                 0
    # 9  2017-04-25    DFDS11   ARIA   100     100                 0
    # 10 2017-04-25    DFDS11   GOOG  1700     900                 0
    # 11 2017-04-26   GDSD114    GEO   150     150               100
    # 12 2017-04-26   GDSD114    HEI    50      50                 0
    # 13 2017-04-26   GDSD114    PWF    50      50               150
    
    ## determine the unfulfilled
    
    SSTableOP <- SSTableAdjusted %>%
      filter(per_ticker_unfulfilled_units != 0) %>%
    
      select(ticker, per_ticker_unfulfilled_units)
    #   ticker per_ticker_unfulfilled_units
    # 1   APPL                          200
    # 2    GEO                          100
    # 3    GWG                          250
    # 4    MFC                          600
    # 5    PWF                          150
    

    【讨论】:

    • 如果我想改变假设从最早日期的投资组合中出售单位,我将如何调整我的变异? @epi99
    • @mannym,我认为您需要将arrange(ticker, -portfolio_units) 修改为arrange(ticker, date) 之类的内容,但您需要确保该日期属于 Date 类(或类似)才能正确订购。包lubridate 擅长此功能,具有mdy 之类的功能,因此在此过程之前添加PTable$date &lt;- mdy(PTable$date) 之类的内容。如果您想要最近的日期,请使用 desc(date)(未测试)
    • 像 POSIXCt 一样工作。还有一件事,你能告诉我你认为剩下的要卖的是什么吗? @epi99
    • @mannym,我认为简单的日期更改不起作用。我已经修改了很多答案,并重新调整了列名以更紧密地匹配。结果现在与您的示例输出匹配。
    • 一切正常。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    相关资源
    最近更新 更多