从多个投资组合中出售股票循环

时间:2017-04-26 21:10:48

标签: r loops dplyr

所以我在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

PTableOP

SSTableOP

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

1 个答案:

答案 0 :(得分: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