証券のリスクとリターンを計算するアプリケーションを作ろう

ファイナンス理論では証券のリターンとリスクを手がかりにポートフォリをを構築します。
ポートフォリオに個別証券をどれだけの割合で組み入れるかを判断するためには、以下のパラメータが必要です。

1. リターン（期待収益率）
2. リスク（標準偏差）
3. 各銘柄についての相関係数

# 要件
シンボルを入力すると、上記パラメータが出力されれば良いので、コンソールアプリケーションでも良いのですが、商品化も視野に入れてるので最初からWebアプリケーションで開発します。
使用する言語は以下を想定します。

1. R
2. PHP
3. HTML

# 設計方針
リスクとリターンを計算するためのヒストリカルデータのサンプリング期間については[様々な議論](https://www.tr.mufg.jp/houjin/jutaku/pdf/u201806_1.pdf)がありますが、三菱信託UFJ銀行は過去 20 年間の月次のリターン実績から算定しているそうなので、これに倣うとしましょう。
計算式は以下の通り

```math
リスク推計値\left(年率標準偏差\right)=\left(n年間の月次リターンの標準偏差\right)×\sqrt{12}\\\\
ただし、n=20
```

しかし、ヒストリカルデータが20年に満たない場合があるので、この際は設定来のデータを利用します。
最長20年間のデータを取得する詳しい方法は以下の記事を御覧ください。

* [Rを使ってYahoo! Financeから最長過去20年間のヒストリカルデータを取得する](https://qiita.com/canopysand/items/ced4dd2f946561d32c59)

ちなみにリターンは年率リターンの平均値で計算します。
相関係数はヒストリカルデータから分散、共分散を計算できるので、追加の情報は不要です。
# Webサーバの構築
[お手軽なWebサーバーの立て方](https://qiita.com/massie_g/items/2913066e596dae197539)というのが公開されていたので、これにしてみましょう。
ついでに[Smarty](https://www.smarty.net/)というPHPテンプレートエンジンもインストールしておきます。
Smartyを使いやすくするために、`Smarty`クラスを継承する`Smarty_PortfolioMaker`クラスを作成する`setup.php`をPHPの`include_path`に設置しておきます。

```php5:setup.php
<?php

// Smartyライブラリを読み込みます
require('Smarty.class.php');

// setup.phpはアプリケーションに必要なライブラリファイルを
// 読み込むのに適した場所です。それをここで行うことができます。例:
// require('guestbook/guestbook.lib.php');

class Smarty_PortfolioMaker extends Smarty
{

   function __construct()
   {

      // クラスのコンストラクタ。
      // これらは新しいインスタンスで自動的にセットされます。

      parent::__construct();

      $this->template_dir = 'C:/xampp/portfoliomaker/templates/';
      $this->compile_dir  = 'C:/xampp/portfoliomaker/templates_c/';
      $this->config_dir   = 'C:/xampp/portfoliomaker/configs/';
      $this->cache_dir    = 'C:/xampp/portfoliomaker/cache/';

      $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
      $this->assign('app_name', 'Portfolio Maker');
   }
}
```

あとはRの環境を用意すれば準備OK。
# PHPとRの結合
入出力の要件定義より、処理順を以下の通り設計しました。

1. PHPで出力したHTMLよりシンボルを入力して送信
2. 入力値をRに渡してヒストリカルデータを取得
3. Rでヒストリカルデータを解析し、リスクとリターンを出力
4. 出力されたデータをPHPで受け取り、HTMLに描画して表示

では作っていきましょう。
# 入力画面
これはHTMLを吐けばいいので簡単。
phpはdisplay関数を呼ぶだけにとどめ、マークアップはtplファイルに任せます。

```php5:input.php
<?php
require_once('portfoliomaker/setup.php');
$smarty = new Smarty_PortfolioMaker;
$smarty->display('input.tpl');
?>
```

```smarty:input.tpl
<!DOCTYPE html>
<html lang=“ja”>

<head>
    <meta charset=“UFT-8”>
    <title>さいきょうのポートフォリオを作ろう！</title>
</head>

<body>
    <h1>ETFのリスクとリターンを検索する</h1>
    <form action="quants.php" method="POST">
        <p>シンボル<input type=“text” name=symbol></p>
        <p><button type=“submit” value=“送信“>送信</button></p>
    </form>
</body>

</html>
```

# Rによる統計解析
ここではphpはさておき、Rだけでスクリプトを書いてみます。
以下の記事を参考にしました。

* [R で米国 ETF パフォーマンス分析](https://qiita.com/five-dots/items/2ddb699a9fc4e151a43a)

```R:analyze_risk_and_return.R
# install.packages("tidyverse", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("tidyquant", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("timetk", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("PerformanceAnalytics", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("GGally", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("ggrepel", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("patchwork", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("formattable", repos = "http://cran.us.r-project.org", dependencies=TRUE)
# install.packages("rjson", repos = "http://cran.us.r-project.org", dependencies=TRUE)
library(tidyquant)
library(tidyverse)
library(timetk)
# library(PerformanceAnalytics)
# library(GGally)
# library(ggrepel)
# library(patchwork)
library(formattable)
library(rjson)

get_start_date <- function(data) {
    data %>%
    summarise(start_date =  min(date)) %>%
    pull(start_date) %>%
    max()
}

align_start_date <- function(data) {
  start_date <- get_start_date(data)
  filter(data, date >= start_date)
}

add_cumret_dd <- function(data) {
  suppressWarnings(
    data %>%
    mutate(cum_ret = cumprod(1 + return) - 1,drawdown = Drawdowns(return))
  )
}

convert_to_xts <- function(data, name_col, value_col) {
  name_col <- enquo(name_col)
  value_col <- enquo(value_col)
  data %>%
    select(date, !!name_col, !!value_col) %>%
    pivot_wider(names_from = !!name_col, values_from = !!value_col) %>%
    tk_xts(-date, date)
}

calc_perf_metrices <- function(data) {
    xts_data <- convert_to_xts(data, symbol, return)

    map_dfr(names(xts_data), function(symbol) {
        ra <- xts_data[, symbol]
        data.frame(
            Symbol  = symbol,
            Sharpe  = round(as.numeric(SharpeRatio(ra, annualize = TRUE, FUN = "StdDev")), 2),
            Avg_Ret = as.numeric(Return.annualized(ra)),
            Cum_Ret = as.numeric(Return.cumulative(ra)),
            StdDev  = as.numeric(StdDev.annualized(ra)),
            MaxDD   = as.numeric(maxDrawdown(ra)),
            stringsAsFactors = FALSE
        )
    }) %>%
    mutate_at(vars(Avg_Ret, Cum_Ret, StdDev, MaxDD), percent, digits = 1) %>%
    arrange(-Sharpe)
}

args <- commandArgs(trailingOnly = TRUE)
symbol <- args[1]
start_date <- paste(as.POSIXlt(Sys.Date())$year + 1880, "-01-01", sep = "")
end_date <- paste(as.POSIXlt(Sys.Date())$year + 1899, "-12-31", sep = "")
rawdata <- tq_get(symbol, from = start_date, to = end_date)

data <- rawdata %>%
group_by(symbol) %>%
tq_transmute(adjusted, mutate_fun = dailyReturn, col_rename = "return") %>%
slice(-1)

data %>%
summarize(start = min(date), end = max(date), na = sum(is.na(return)))

analysis_result <- list()
analysis_result$data <- data %>%
    align_start_date() %>%
    add_cumret_dd()

analysis_result$pref_table <- calc_perf_metrices(analysis_result$data)
cat(toJSON(analysis_result$pref_table))
```

まず、phpの実行ユーザ権限でパッケージをインストールする必要があるので、初回実行時だけ`install.packages()`関数でパッケージをインストールします。
インストールログはApacheのerror.logに出力されるので、これをtailで流しながらインストールすると安心です。
メインプログラムは以下の手順で処理を実行します。

1. 引数からティッカーを取得する
2. ティッカーのヒストリカルデータをYahoo!Financeからダウンロードする
3. ヒストリカルデータからリターンを計算し、行列に追加する
4. ヒストリカルデータからドローダウンを計算し、行列に追加する
5. 各種指標を計算し、`toJSON()`関数でエンコードして`cat()`関数で標準出力する

#解析結果の表示
POSTされたシンボルをRに渡し、結果を表示する処理をphpに記述します。
[こちらのサイト](http://mi2yo4.blog136.fc2.com/blog-entry-80.html)を参考に開発します。

```php5:quants.php
<?php
require_once('portfoliomaker/setup.php');
$smarty = new Smarty_PortfolioMaker;
if (isset($_POST['ticker'])) {
    $ticker = $_POST['ticker'];
    $enc_ticker = json_encode($ticker);

    if (file_exists('C:/xampp/php/pear/portfoliomaker/R/analyze_risk_and_return.R')) {
        $cmd = "Rscript.exe --vanilla C:/xampp/php/pear/portfoliomaker/R/analyze_risk_and_return.R $enc_ticker";
        exec($cmd, $response);
        $res = json_decode($response[4]);
        $smarty->assign('ticker', $symbol);
        $smarty->assign('Avg_Ret', $res->Avg_Ret);
        $smarty->assign('StdDev', $res->StdDev);
    } else {
        print_r("Rスクリプトがないよ。");
        print_r(__DIR__);
    }
}
$smarty->display('quants.tpl');
?>
```
今回はRに渡す値が1つしかないので、JSON形式である必要は全く無いですが、後学のためにフォームからPOSTされた値を`json_encode()`関数でJSON形式にエンコードしてから、Rscript.exeの引数に渡します。
実行するスクリプトは先程作った`analyze_risk_and_return.R`です。
出力したい値を`assign()`関数で割り当てておき、`quants.tpl`でマークアップします。

```smarty:quants.tpl
<!DOCTYPE html>
<html lang = “ja”>
    <head>
        <meta charset = “UFT-8”>
        <title>さいきょうのポートフォリオを作ろう！</title>
    </head>
    <body>
        <h1>ETFのリスクとリターン</h1>
        <div>
            <p>シンボル：{$symbol}</p>
            <p>リスク：{$StdDev}</p>
            <p>リターン：{$Avg_Ret}</p>
        </div>
    </body>
</html>
```

#まとめ
これでコーディングは完了しました。
あとは、`input.php`にお目当てのティッカーを入力して送信すれば、`quants.php`がヒストリカルデータを引っ張ってきてリスクとリターンを出力してくれます。
次回は複数の銘柄を入力し、相関係数を出力するプログラムに発展させてみましょう。