Не хочешь депозит 6,5? Расчет нормы доходности акций и полной доходности с помощью Moex API и парсера дивидендов

    Немного о тексте ниже




    Самый ленивый портфельный инвестор обычно поступает так: идет к финансовому управляющему, они вместе составляют профиль инвестора и на основании этого профиля они собирают портфель из активов, которые соответствуют тем показателям риска\доходности, которые портфельный инвестор готов принять.

    Если инвестор очень долгосрочный и портфель составлен правильно, то он может покупать бумаги в любое время и по любой цене, 10-тилетний временной промежуток сгладит разницу за счет див.выплат (конечно мы должны искать ценные бумаги с постоянным денежным потоком).
    Рассмотрим ситуацию, в которой вам надо найти ценные бумаги (далее я буду подразумевать конкретный тип бумаг — акции, с облигациями все понятно, там купон), которые приносит в виде дивидендов денежный поток, удовлетворяющий вашему финансовому плану. Самый простой пример — найти акцию, денежный поток которой превышает значение инфляции, т.е. 4% (по данным Росстата)

    Давайте рассмотрим второй фактор из этой пары риск/доходность — собственно доходность

    Доходность акции это показатель, который позволяет оценить, какую прибыль можно получить с момента приобретения ценной бумаги. Доходность может быть не только положительной, но и отрицательной – в том случае, когда акция принесла инвестору убыток. В общем виде доходность акции рассчитывает по следующей простой формуле:

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


    Агрегаторы


    Сразу приведу пару ресурсов, которые уже содержат в себе те данные, которые нам нужны. Там приведены данные по доходностям ценных бумаг и факторы, на которые надо обратить внимание при их покупке. Сам я тоже периодически заглядываю на эти ресурсы:Доход.ру и Инвестиционный раздел Смартлаба.

    Вы можете спокойно пользоваться ими, я же поставил себе задачу автоматизировать некий процесс + иметь возможность работать с данными по дивидендным выплатам за некий возможный период времени.

    Пишем парсер


    Перебрав несколько вариантов, я остановился на phpQuery, хотя до этого попытался реализовать парсер на Simple HTML DOM. Результат обрабатывался очень долго, поэтому пришлось сменить. Данные парсим с сайта investfunds.ru

    Код парсера
    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; 
        }


    результатом работы функции будет массив с данными по одному эмитенту. Далее, я импортирую результат в companies.json

    импорт
    $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));
    


    Пример массива
    [{"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}
                }
      }]
    


    Минусы парсера: сначала я думал, что придется спарсить около 1000 страниц, потому что после 800 мне стали попадаться только доп.эмиссии. Но потом, не найдя одного из эмитентов, я решил продолжить парсинг и выяснилось, что даже и после 5к страниц может что-то попадаться. Решение — переписать парсер с использованием multicurl для скорости обработки. До этого у меня руки не дошли (начал читать), но по правильному, стоило бы поступить именно так. Может кто-то из читателей мне поможет. Опять же, базу с дивами можно обновлять раз в пол года. Этого хватит, если вы оперируете годовыми доходностями.

    Высчитываем норму доходности и полную доходность акции с момента покупки


    Формулу я уже привел выше. Для автоматизации я написал скрипт, который использует исходные данные, вводимые вручную и считает требуемые показатели.

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

    Для удобства я написал небольшую функцию. которая по тикеру находит данные эмитента в json

    Поиск по тикеру
    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;                
                }
            }
        }


    Теперь мы можем посчитать интересующие нас данные. Для получения текущей цены (переменная $today_price) я использую функцию, в которой я писал в своем предыдущем посте и которая использует API Московской биржи. Все формулы взяты из вот этой статьи.

    $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; //целевая цена покупки
    

    Теперь немного анализа получившихся результатов. Для примера я беру две крупных компании, входящих INDEX MSCI RUSSIA

    Газпром


    и Алроса (Допустим, мы ее брали по 60р. в 2015 году.)



    Как видите, несмотря на то, что цена акции газпрома практически не отличается от цены покупки, мы все равно имеем доходность 12% за счет дивидендов. У Алросы дела обстоят еще лучше. Можем пересчитать для доходности ставок по депозитам с сайта банки.ру из списка банков top-50. Сейчас банки дают нам 6,5%





    Соответственно, так вы можете, варьируя нужную норму доходности, понять удовлетворяет ли текущая цена акции вашим запросам и вашим финансовым целям.

    Замечу, что как и в прошлой статье, это лишь нахождение одного из факторов, влияющих на принятие решения.

    Многие инвесторы делают вышеописанные расчеты в Excel. Этот инструмент предоставляет множество формул для расчетов прибыли, денежных потоков и т.д. Но я ставил целью автоматизировать сбор данных по дивидендам и автоматизированную обработку этих данных.
    Статья в этот раз включает меньше теории и больше кода потому, что теория очень обширна, а привязать данную задачу к общей теории построения портфеля — надо писать цикл статей. Да и формат Хабра не подразумевает написание чисто инвестиционных статей, тем более сейчас на просторах сети их огромное множество.

    Предыдущая статья
    Спасибо за внимание!
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 10

      +1
      Все классно, но основные параметры:
      1) история в прошлом не дает основания делать 100% прогноз в будущее
      2) выплата дивидендов в РФ слишком зависит от государственной политики и на нее сложно опираться в прогнозах
      3) более-менее прогноз можно делать по ОФЗ, но и там тоже много нюансов
        +1

        Спасибо за комментарий.


        1. Если мы принимаем во внимание, что рынок абсолютно справедлив(но это не так, конечно), то предполагается, что компания будет наращивать чистую прибыль и, как следствие, будет увеличивать размер дивидендов. Как правило, их размер привязан к размеру прибыли. В РФ есть компании, которые достаточно строго следуют этому правилу. Поэтому, тут не совсем прогнозирование. Логика такая: компания стабильная? Да. Дивы увеличивает? Да. Текущая див.доходность нас устраивает? Да. Значит берём.
        2. Надо формировать портфель так, чтобы компании имели низкую корреляцию с этим фактором. Газпром, например, имеет высокую корреляцию, а Алроса больше зависит от экспортных цен на алмазы, чем от полит.событий. Поэтому, при формировании портфеля мы должны учесть риски и факторы, в том числе и политический.
        3. Все-таки повторюсь, это не прогноз. Прогноз был бы, если бы я считал целевые цены продажи и прогнозировал выручку, в зависимости от цен на продукцию компании. В этой статье я этого не касаюсь.
          0
          Размер дивидендов никогда не постоянен и не модет давать фиксированный доход. Для фиксированого дохода имеются облагции и тем кому фиксированный доход нужен — акциями не заморачиваются. Те кто включают акции в портфель расчитывают на повышение цены акции в первую очередь а на дивиденды расчитывают — в самую последнюю
            0

            Все верно. Я описываю одну из практик — "дивидендное инвестирование". Дело, конечно же, в суммах. Если у вас 10млн., вы еще можете перекладывать их между компаниями второго эшелона, пытаясь поймать волну и получать прибыль в виде дивов. Если у вас 200млн.$, то вы купите евробонды и газпром, недвижимости и не будете ни о чем думать вообще. Стратегий множество.
            Опять же, многие держат подушку из облигаций и во время кризиса на них докупаются акции. Когда рынок перегревается, то совершается обратный процесс — акции продаются, и покупаются облигации.

            0
            1) Так вы стабильность же не считаете?
            3) Если уж вы берёте данные за прошлые годы — в 2015 и инфляция была то ли 20%, то ли 50%
              0

              Не считаю, в рамках этой статьи. В прошлой статье я указывал на ресурсы, где можно проанализировать данный показатель.
              По поводу инфляции, вы знаете, каждую кризисную ситуацию надо обсуждать отдельно. Конечно, логично, что когда рынок падает в пропасть, вы не можете ждать огромных дивидендов. Зато, вы можете в кризис купить дёшево бумаги, которые кроме дивидендов еще и дадут вам курсовой рост. Так, сбер с 2014 по 2016 дал бы вам 100%+. Ну, как то так..

                0
                1) если мы экстраполируем кризисное прошлое, где сбер с 2014 по 2016 дал бы 100%+, то надо брать сбер.
                2) Если мы предсказываем будущее с инфляцией в 4%, то нам уже не надо брать сбер.
                3) Если мы предсказываем стабильное будущее по данным кризисного прошлого — это странно
                  0

                  Единственное, что я допускаю, что дивиденды будут увеличиваться вслед за прибылью, что соответствует понятию правильного менеджмента в правильной рыночной экономике. Всем остальным я не занимался:) Ни экстраполировал прошлое, ни предсказывал будущее. Инфляцию обещает минфин, все вопросы к ним. Но и то, я ее взял чисто для примера в расчетах

                    0
                    Тогда при чем тут цена покупки в 2015?
                      0

                      В исходных данных есть переменная "год покупки". Я его взял для примера, что данные реальны и что функция считает данные за несколько лет. Можно взять на год раньше или на год больше, другие тикеры, доходности будут другие. Это всего лишь пример рассчетов. Я никого не убеждаю, что алроса будет давать огромные дивы или расти в цене. Просто она есть у меня в портфеле, поэтому так и получилось. О чем знал, о том и писал.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое