Do you want a 6.5 deposit? Calculation of the rate of return on shares and full profitability using the Moex API and the dividend parser

    A bit about the text below




    The laziest portfolio investor usually does this: he goes to the financial manager, they together make up the investor profile and based on this profile they collect a portfolio of assets that correspond to the risk / return indicators that the portfolio investor is ready to accept.

    If the investor is very long-term and the portfolio is composed correctly, then he can buy securities at any time and at any price, a 10-year time period will smooth out the difference due to dividend payments (of course, we should look for securities with a constant cash flow).
    Consider the situation in which you need to find securities (hereinafter I will mean a specific type of securities - stocks, everything is clear with bonds, there is a coupon), which brings in the form of dividends a cash flow that satisfies your financial plan. The simplest example is to find a stock whose cash flow exceeds the inflation value, i.e. 4% (according to the Federal State Statistics Service)

    Let's look at the second factor of this risk / return pair - the return itself.

    The stock return is an indicator that allows you to evaluate how much profit you can get from the moment you purchase a security. Profitability can be not only positive, but also negative - in the case when the stock brought the investor a loss. In general, stock returns are calculated using the following simple formula:

    $ V = (\ frac {D} {P}) \ times 100 \% $


    Aggregators


    I’ll give you a couple of resources that already contain the data that we need. It contains data on the yield of securities and factors that you need to pay attention to when buying them. I myself also periodically look at these resources: Income.ru and the Investment section of Smartlab .

    You can safely use them, but I set myself the task of automating a certain process + to be able to work with data on dividend payments for a certain possible period of time.

    Writing a parser


    After going through several options, I settled on phpQuery, although before that I tried to implement a parser on the Simple HTML DOM. The result was processed for a very long time, so I had to change it. Parsim data from investfunds.ru

    Parser code
    public function getDivsFromCode($code){ //код эмитента - номер эмитента на сайте, откуда берутся данные.
         include_once './phpQuery.php';
         if ( $curl = curl_init () ) //инициализация сеанса
           {
            curl_setopt ($curl, CURLOPT_URL, 'http://stocks.investfunds.ru/stocks/'.$code.'/dividend/');//указываем адрес страницы
            curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt ($curl, CURLOPT_POST, true);
            curl_setopt ($curl, CURLOPT_HEADER, 0);
            $result = curl_exec ($curl);//выполнение запроса
            curl_close ($curl);//закрытие сеанса
          }
        $html = phpQuery::newDocumentHTML($result);
        phpQuery::selectDocument($html);
        $a = [1,3,5];            //номера столбцов из которых надо извлечь данные(год, дата выплаты и сумма)
        $emitent_string = htmlentities(pq('h1')->text(),ENT_COMPAT,'UTF-8');
        if ($emitent_string === ""){
            $divs['emitent'] = 'Нет эмитента';
            return $divs;
        }
        $re = [' акция привилегированная, Дивиденды', ' акция обыкновенная, Дивиденды',' акция обыкновенная',' акция привилегированная'];
        $emi = str_replace($re,'',$emitent_string);
        $divs['emitent'] = $emi;
        $divs['code'] = $code;
        /*находим количество лет, когда выплачивали дивы*/
        $i = pq('[cellpadding="0"] tr td:nth-child(1)');
        $l = substr_count($i,'td style');
        /*помечаем, что эмитент не выплачивал дивы*/
        if ($l === 0){
        $divs['data']= 'No divs';
        return $divs;
        }
        /******играемся с регулярными выражениями и css************************/
        for ($i =3;$i<$l+3;$i++){
            foreach ($a as $j){
                switch ($j) {
                    case 1:
                        $divs['data'][$i-2]['year'] = str_replace(' ','',htmlentities(pq("[cellpadding='0'] tr:nth-child($i) td:nth-child($j)")->text(),ENT_COMPAT,'UTF-8'));
                        break;
                    case 3:
                        $divs['data'][$i-2]['date'] = str_replace(' ','',htmlentities(pq("[cellpadding='0'] tr:nth-child($i) td:nth-child($j)")->text(),ENT_COMPAT,'UTF-8'));
                        break;
                    case 5:
                        $string = htmlentities(pq("[cellpadding='0'] tr:nth-child($i) td:nth-child($j)")->text(),ENT_SUBSTITUTE,'UTF-8');
                        $re = '/[ \s]|[руб]/';
                        $divs['data'][$i-2]['price'] = (float)preg_replace($re,'',$string);
                        break;
                    default:
                        break;
                }
            }
         }
               /*возвращаем массив, который содержит в себе название эмитента, год выплаты, дату выплаты и сумму выплаты */
        return $divs; 
        }


    the result of the function will be an array with data for one issuer. Next, I import the result into companies.json

    import
    $divs = $emitent->getDivsFromCode($i);
    if ($divs['emitent'] != 'Нет эмитента'){
            array_push($json_div, $divs);
        }
    }
    file_put_contents('companies_part1.json',json_encode($json_div,JSON_UNESCAPED_UNICODE));
    


    Array Example
    [{"emitent":"АВТОВАЗ, (RU0009071187, AVAZ)",
       "code":3,
       "data":
                {"1": {"year":"2007","date":"16.05.2008","price":0.29},
                  "2": {"year":"2006","date":"06.04.2007","price":0.1003},
                  "3": {"year":"2005","date":"07.04.2006","price":0.057}
                }
      }]
    


    Cons of the parser: at first I thought that I would have to parse about 1000 pages, because after 800 I only came across additional issues. But then, not finding one of the issuers, I decided to continue parsing and it turned out that even after 5k pages something might come across. The solution is to rewrite the parser using multicurl for processing speed. Before that, my hands didn’t reach (I started reading), but in the right way, it would be worth doing just that. Maybe one of the readers will help me. Again, the base with the divas can be updated once every half a year. This is enough if you operate on annual returns.

    We calculate the rate of return and the full return on the stock from the time of purchase


    I have already given the formula above. For automation, I wrote a script that uses the initial data entered manually and considers the required indicators.

    $name = 'GAZP';         //Тикер эмитента
    $year_buy = 2015;      //Год покупки актива
    $buy_price = 130;        //Цена покупки актива
    $year_last_div = 2016;  //Год последних выплаченных диви
    $v_need = 4;           //требуемая доходность
    

    For convenience, I wrote a small function. which by the ticker finds the issuer data in json

    Ticker Search
    public function getDivsFromName($name){
             $file = file_get_contents('companies.json');
            $array = json_decode($file,true);
            foreach ($array as $emitent) {
                if ((stristr($emitent['emitent'],$name))&&(!stristr($emitent['emitent'],$name.'-'))){
                    return $emitent;                
                }
            }
        }


    Now we can calculate the data we are interested in. To get the current price (the variable $ today_price ) I use a function in which I wrote in my previous post and which uses the Moscow Exchange API. All formulas are taken from this article.

    $emitent = new emitent();
    $v_today;           //Текущая норма прибыли;
    $v_need = $v;   //Требуемая норма доходности;
    $div = $emitent->getDivsFromName($name);
    $sum = $emitent->getSumDivs($year_buy, $div);
    $last_div = $emitent->getSumDivs($year_last_div, $div,1);
    //Считаем доходность c момента покупки
    /*r = (D + (P1 - P0))/P0 * 100%
     * P0 - цена покупки
     * P1 - цена продажи
     * D - сумма дивидендов
     *  */
    $today_price = $emitent->getPrice($name, '.json');
    $r = ($sum + ($today_price-$buy_price))/$buy_price*100;
    $v_today = $last_div/$today_price*100;
    $P = ($last_div/$v_need)*100; //целевая цена покупки
    

    Now a little analysis of the results. As an example, I take two large companies, including INDEX MSCI RUSSIA

    Gazprom


    and Alrosa (for example, let's take it at 60 rubles each in 2015.)



    As you can see, despite the fact that the price of Gazprom shares is practically the same as the purchase price, we still We have a yield of 12% due to dividends. Alrosa is doing even better. We can recalculate for profitability of rates on deposits from the site banks.ru from the list of banks top-50. Now banks give us 6.5%.





    Accordingly, this way, by varying the required rate of return, you can understand whether the current price of the stock satisfies your needs and your financial goals.

    I note that, as in the previous article, this is only the finding of one of the factors that influence decision making.

    Many investors do the above calculations in Excel. This tool provides many formulas for calculating profits, cash flows, etc. But my goal was to automate the collection of dividend data and the automated processing of this data.
    This time, the article includes less theory and more code because the theory is very extensive, and to tie this problem to the general theory of building a portfolio - you need to write a series of articles. Yes, and the Habr format does not imply writing purely investment articles, especially now there are a lot of them in the vastness of the network.

    Previous article
    Thank you for your attention!

    Also popular now: