これはかなり高度なデータ操作に関する質問です。R には多くの強力なデータ操作ツールがあり、(確かにかなり鈍い) dyncouponbonds オブジェクトを準備するために R から離れる必要はありません。実際、別の言語から構造を取得してから dyncouponbonds に変換することは、単により多くの作業になるため、実際にはすべきではありません。
最初に確認することは、あなたが lapply 関数に精通していることです。存分に活用していただきます。これを使用して、実際の dyncouponbonds である、couponbonds オブジェクトのリストを作成します。しかし、クーポン債オブジェクトの作成は、主に債券の ISIN とキャッシュフローの日付に関連付けられた各キャッシュフローを必要とする CASHFLOWS サブリストのため、少し難しくなります。これには、lapply とかなり高度な添え字を使用します。サブセット機能も便利です。
この質問は、どこからデータを取得するかにも大きく依存します。Bloomberg からデータを取得することは、主に BDS 関数と各債券の「DES_CASH_FLOW」フィールドを使用して履歴をさかのぼる必要があるため、自明ではありません。そのキャッシュフローを取得します。私が履歴と言うのは、dyncouponbonds を使用している場合は、過去の利回り曲線分析を行いたいと思うからです。BDS 関数の「SETTLE_DT」フィールドを、BDP 関数とフィールド「FIRST_SETTLE_DT」を使用して債券に対して受け取った値にオーバーライドする必要があります。そうしないと、今日からしか返されず、履歴分析には適していません)。しかし、私は脱線します。ブルームバーグを使用していない場合は、どこにいるかわかりません」
次に、各債券の静的データ、つまり満期、ISIN、クーポン レート、発行日を取得する必要があります。また、過去の価格と経過利息のデータが必要になります。ブルームバーグを使用する場合も、BDP 関数を使用して、以下のコードに表示されるフィールドと、bbdh としてラップした履歴データ関数 BDH を使用します。あなたがブルームバーグのユーザーであると仮定すると、コードは次のとおりです。
bbGetCountry <- function(cCode, up = FALSE) {
# this function is going to get all the data out of bloomberg that we need for a
# country, and update it if ncessary
if (up == TRUE) startDate <- as.Date("2012-01-01") else startDate <- histStartDate
# first get all the curve members for history
wdays <- wdaylist(startDate, Sys.Date()) # create the list of working days from startdate
actives <- lapply(wdays, function(x) {
bds(conn, BBcurveIDs[cCode], "CURVE_MEMBERS", override_fields = "CURVE_DATE",
override_values = format(x, "%Y%m%d"))
})
names(actives) <- wdays
uniqueActives <- unique(unlist(actives)) # there will be puhlenty duplicates. Get rid of them
# now get the unchanging bond data
staticData <- bdp(conn, uniqueActives, bbStaticDataFields)
# now get the cash flowdata
cfData <- lapply(uniqueActives, function(x) {
bds(conn, x, "DES_CASH_FLOW_ADJ", override_fields = "SETTLE_DT",
override_values = format(as.Date(staticData[x, "FIRST_SETTLE_DT"]), "%Y%m%d"))
})
names(cfData) <- uniqueActives
# now for historic data
historicData <- lapply(bbHistoricDataFields, function(x) bbdh(uniqueActives, flds = x, startDate = startDate))
names(historicData) <- bbHistoricDataFields # put the names in otherwise we get a numbered list
allDates <- as.Date(index(historicData$LAST_PRICE)) # all the dates we will find settlement dates for for all bonds. No posix
save(actives, file = paste("data/", cCode, "actives.dat", sep = "")) #save all the files now
save(staticData, file = paste("data/", cCode, "staticData.dat", sep = ""))
save(cfData, file = paste("data/", cCode, "cfData.dat", sep = ""))
save(historicData, file = paste("data/", cCode, "historicData.dat", sep = ""))
#save(settleDates, file = paste("data/", cCode, "settleDates.dat", sep = ""))
assign(paste(cCode, "data", sep = ""), list(actives = actives, staticData = staticData, cfData = cfData, #
historicData = historicData), pos = 1)
}
上記で使用する bbdh 関数は、Rbbg ライブラリの bdh 関数のラッパーであり、次のようになります。
bbdh <- function(secs, years = 1, flds = "last_price", startDate = NULL) {
#this function gets secs over years from bloomberg daily data
if(is.null(startDate)) startDate <- Sys.Date() - years * 365.25
if(class(startDate) == "Date") stardDate <- format(startDate, "%Y%m%d") #convert date classes to bb string
if(nchar(startDate) > 8) startDate <- format(as.Date(startDate), "%Y%m%d") # if we've been passed wrong format character string
rawd <- bdh(conn, secs, flds, startDate, always.display.tickers = TRUE, include.non.trading.days = TRUE,
option_names = c("nonTradingDayFillOption", "nonTradingDayFillMethod"),
option_values = c("NON_TRADING_WEEKDAYS", "PREVIOUS_VALUE"))
rawd <- dcast(rawd, date ~ ticker) #put into columns
colnames(rawd) <- sub(" .*", "", colnames(rawd)) #remove the govt, currncy bits from bb tickers
return(xts(rawd[, -1], order.by = as.POSIXct(rawd[, 1])))
}
国コードは、2 文字の名前をブルームバーグの利回り曲線の説明に関連付ける構造に由来します。
BBcurveIDs <- list(PO = "YCGT0084 Index", #Portugal
DE = "YCGT0016 Index",
FR = "YCGT0014 Index",
SP = "YCGT0061 Index",
IT = "YCGT0040 Index",
AU = "YCGT0001 Index", #Australia
AS = "YCGT0063 Index", #Austria
JP = "YCGT0018 Index",
GB = "YCGT0022 Index",
HK = "YCGT0095 Index",
CA = "YCGT0007 Index",
CH = "YCGT0082 Index",
NO = "YCGT0078 Index",
SE = "YCGT0021 Index",
IR = "YCGT0062 Index",
BE = "YCGT0006 Index",
NE = "YCGT0020 index",
ZA = "YCGT0090 Index",
PL = "YCGT0177 Index", #Poland
MX = "YCGT0251 Index")
したがって、bbGetCountry は、すべて次のブルームバーグ フィールドから、actives、staticData、dynamicData、historyData と呼ばれる 4 つの異なるデータ構造を作成します。
bbStaticDataFields <- c("ID_ISIN",
"ISSUER",
"COUPON",
"CPN_FREQ",
"MATURITY",
"CALC_TYP_DES", # pricing calculation type
"INFLATION_LINKED_INDICATOR", # N or Y, in R returned as TRUE or FALSE
"ISSUE_DT",
"FIRST_SETTLE_DT",
"PX_METHOD", # PRC or YLD
"PX_DIRTY_CLEAN", # market convention dirty or clean
"DAYS_TO_SETTLE",
"CALLABLE",
"MARKET_SECTOR_DES",
"INDUSTRY_SECTOR",
"INDUSTRY_GROUP",
"INDUSTRY_SUBGROUP")
bbDynamicDataFields <- c("IS_STILL_CALLABLE",
"RTG_MOODY",
"RTG_MOODY_WATCH",
"RTG_SP",
"RTG_SP_WATCH",
"RTG_FITCH",
"RTG_FITCH_WATCH")
bbHistoricDataFields <- c("PX_BID",
"PX_ASK",
#"PX_CLEAN_BID",
#"PX_CLEAN_ASK",
"PX_DIRTY_BID",
"PX_DIRTY_ASK",
#"ASSET_SWAP_SPD_BID",
#"ASSET_SWAP_SPD_ASK",
"LAST_PRICE",
#"SETTLE_DT",
"YLD_YTM_MID")
これで、これらすべてのデータ構造を使用して、クーポンボンド オブジェクトを作成する準備が整いました。
createCouponBonds <- function(cCode, dateString) {
cdata <- get(paste(cCode, "data", sep = "")) # get the data set
today <- as.Date(dateString)
settleDate <- today
daycount <- 0
while(daycount < 3) {
settleDate <- settleDate + 1
if (!(weekdays(settleDate) %in% c("Saturday", "Sunday"))) daycount <- daycount + 1
}
goodbonds <- subset(cdata$staticData, COUPON != 0 & INFLATION_LINKED_INDICATOR == FALSE) # clean out zeros and tbills
goodbonds <- goodbonds[rownames(goodbonds) %in% cdata$actives[[dateString]][, 1], ]
stripnames <- sapply(strsplit(rownames(goodbonds), " "), function(x) x[1])
pxbid <- cdata$historicData$PX_BID[today, stripnames]
pxask <- cdata$historicData$PX_ASK[today, stripnames]
pxdbid <- cdata$historicData$PX_DIRTY_BID[today, stripnames]
pxdask <- cdata$historicData$PX_DIRTY_ASK[today, stripnames]
price <- as.numeric((pxbid + pxask) / 2)
accrued <- as.numeric(pxdbid - pxbid)
cashflows <- lapply(rownames(goodbonds), function(x) {
goodflows <- cdata$cfData[[x]][as.Date(cdata$cfData[[x]][, "Date"]) >= today, ]
#gfstipnames <- sapply(strsplit(rownames(goodflows), " "), function(x) x[1]) dunno if I need this
isin <- rep(cdata$staticData[x, "ID_ISIN"], nrow(goodflows))
cf <- apply(goodflows[, 2:3], 1, sum) / 10000
dt <- as.Date(goodflows[, 1])
return(list(isin = isin, cf = cf, dt = dt))
})
isinvec <- unlist(lapply(cashflows, function(x) x$isin))
cfvec <- as.numeric(unlist(lapply(cashflows, function(x) x$cf)))
datevec <- unlist(lapply(cashflows, function(x) x$dt))
govbonds <- list(ISIN = goodbonds$ID_ISIN,
MATURITYDATE = as.Date(goodbonds$MATURITY),
ISSUEDATE = as.Date(goodbonds$FIRST_SETTLE_DT),
COUPONRATE = as.numeric(goodbonds$COUPON) / 100,
PRICE = price,
ACCRUED = accrued,
CASHFLOWS = list(ISIN = isinvec, CF = cfvec, DATE = as.Date(datevec)),
TODAY = settleDate)
govbonds <- list(govbonds)
names(govbonds) <- cCode
class(govbonds) <- "couponbonds"
return(govbonds)
}
cacheflows <- lapply... 関数をよく見てください。これは、サブリストを作成する場所であり、質問への回答の中心となるためです。中間データ構造を構築することに決めました。私は 1 つの可能性だけを示しました。私の答えは複雑ですが、問題は非常に複雑です。必要なすべてのコードがこの回答にも含まれているわけではありません。いくつかのヘルパー関数が欠落していますが、ご連絡いただければ喜んで提供させていただきます。確かに、コア関数の骨組みはすべてここにあります。実際、問題の多くは、最初にデータを取得し、適切に構造化することです。データの一部は各結合について静的であり、一部は動的であり、一部は履歴であると正しく推測できます。そのため、中間データ構造の次元は、クーポンボンド オブジェクトのさまざまな部分で異なります。それをどのように表現するかはあなた次第ですが、必要に応じてボンド ID を介してリンクされた、それぞれに個別のリスト/データ フレームを使用しました。
上記の関数は日付文字列を取得するため、上記のラップリーを使用して履歴データ ポイントごとに実行できます。
spl <<- lapply(dodates, function(x) createCouponBonds("SP", x))
names(spl) <<- lapply(spl, function(x) x$SP$TODAY)
class(spl) <- "dyncouponbonds"
ほらね。あなたはそれを求めた....
ブルームバーグを使用していない場合、入力データ構造は大きく異なりますが、最初に述べたように、lapply と sapply に精通してください。もちろん、この問題を解決する方法は他にもたくさんありますが、ブルームバーグでは上記の方法が有効です。このコードを理解すれば、他のデータ ソースに対して何を行っているかがわかります。
最後に、ブルームバーグとのインターフェイスには findata.org のRBBGパッケージが使用されていることに注意してください。