Как человек, который годами занимается алгоритмической торговлей, я создал почти все приемы, описанные в книге. Я работал с сотнями индикаторов и множеством статистических тестов и наблюдений за рынком.

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

Создание базы данных новостей

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

Считается, что у растущих компаний есть хорошие шансы для значительного расширения в течение следующих нескольких лет либо потому, что у них есть продукт или линейка продуктов, которые, как ожидается, будут хорошо продаваться, либо потому, что они, как представляется, работают лучше, чем многие из их конкурентов, и, таким образом, ожидается, что они получат преимущество на своем рынке. — Инвестопедия

Мы можем установить категорию Google как новости и ввести поисковый запрос «лучшие акции роста для инвестиций». Это даст нам множество статей для анализа данных.

Теперь давайте создадим парсер с помощью Selenium для сбора информации об этих статьях. Вам также понадобится любая последняя версия Python на вашем устройстве. Нам нужно сначала импортировать несколько библиотек.

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd

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

# The number of pages you want to scan, 
# since each page has roughly 10 articles this should be ample
num_pages = 30

# Create driver
driver = webdriver.Chrome()

# URL of the webpage to scrape
url = " *** REPLACE *** "  # Replace with your desired webpage URL

# Create dataframe to store important information
newsDf = pd.DataFrame(columns=["Organization", "Link", "Title", "Date"])

# Call driver to get webpage
driver.get(url)

После того, как вы откроете веб-страницу, у нас возникнут две основные проблемы.

  1. Сбор всей информации со страницы
  2. Переход на следующую страницу

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

Изучив страницу, мы можем увидеть, что все данные находятся внутри этого разделителя, поэтому давайте переместим элемент драйвера в этот разделитель, найдя его XPath (щелкните левой кнопкой мыши, скопируйте XPath).

div_xpath = """//*[@id="rso"]/div/div"""
div_element = driver.find_element(By.XPATH, div_xpath)

Теперь давайте перейдем к получению данных из каждой статьи. На вкладке проверки мы видим, что каждая статья находится в своем собственном разделителе и аккуратно помечена собственными именами классов. Мы можем извлечь все эти элементы с помощью функции find_elements и добавить их в наш фрейм данных.

# Get all the links from specific div
org = driver.find_elements(By.CLASS_NAME, 'NUnG9d')
links = div_element.find_elements(By.TAG_NAME, "a")
titles = driver.find_elements(By.CLASS_NAME, 'nDgy9d')
dates = driver.find_elements(By.CLASS_NAME, 'LfVVr')

# Add each row to dataframe
for containerNum in range(len(links)):
    newsDf.loc[len(newsDf)] = [
      org[containerNum].text, 
      links[containerNum].get_attribute("href"), 
      titles[containerNum].text, 
      dates[containerNum].text
    ]

# Update csv in case of error
newsDf.to_csv("news.csv")

Теперь осталось только перейти на следующую страницу. Хотя есть много способов сделать это, самый простой — получить список всех ссылок с номерами страниц в нижней части страницы и использовать последнюю ссылку, которая является ссылкой «следующая страница».

# Gets the URL of the next google page
next_xpath = """//*[@id="botstuff"]/div/div[2]"""
next_element = driver.find_element(By.XPATH, next_xpath)
links = next_element.find_elements(By.TAG_NAME, "a")
next_link = links[-1].get_attribute("href")

# Go to next page
driver.get(next_link)

Наконец, просто заверните код в цикл for, который будет продолжаться до тех пор, пока не будут посещены все страницы или столько, сколько вы хотите!

Получение всех упомянутых акций

Сначала нам, конечно, нужно получить текст наших статей на наш локальный компьютер, чтобы мы могли извлечь из него данные тикера. Для этого мы будем использовать запросы, которые намного быстрее и легче по сравнению с аналогом Selenium. И мы будем использовать Beautiful Soup для сбора данных html из источника.

# Importing the needed libraries
import re
import time
import nltk
import requests
import pandas as pd
from bs4 import BeautifulSoup

Теперь нам нужно просмотреть нашу базу данных и очистить каждую статью. Следующий код предназначен для одной итерации цикла for, где i будет от 0 до длины набора данных вашей статьи. Мы также позволим машине повторить попытку связи, если ссылка не может быть достигнута.

# Get link
link = newsdf["Link"][i]
print("Link #{}: {}".format(i, link))
time.sleep(1) #Make sure we are giving requests enough time

try:
    # Get page source
    r = requests.get(link, timeout=10)
    print("Status: ", r.status_code)

    # Retry if status code is not 200
    tryCount = 0
    while r.status_code != 200 and tryCount < 5:
        print("Retrying...", tryCount)
        r = requests.get(link, timeout=10)
        time.sleep(1)
        tryCount += 1

except:
    # If error, skip link
    print("Error")
    continue

Далее нам нужно использовать bs4 и re в сочетании с запросами для извлечения основного текста из статьи.

#Get page source and tokenizes data
html = r.content

# Create BeautifulSoup object
soup = BeautifulSoup(html, "html.parser")

# Get all text from page
pageSource = " ".join(soup.strings)
pageSource = re.sub(r"\s+", " ", pageSource)

Окончательно! Последний шаг — найти способ извлечь все данные тикера из статей. Здесь есть два основных подхода:

  1. Подход ИИ
  2. Подход к токенизации

Хотя подход ИИ более эффективен и менее подвержен ошибкам, он дороже, и для больших наборов данных это может быть проблемой. С другой стороны, подход к токенизации гораздо более подвержен ошибкам, однако это можно исправить при постобработке. Мы кратко рассмотрим оба.

Подход ИИ

Это довольно просто. Мы можем использовать API ChatGPT и просто запросить у него подсказку: Найти все акции, упомянутые в этой статье, которые имеют положительные настроения, и вернуть их только в виде строк в списке, разделенном Python: {Article Body}.

Хотя ChatGPT может возвращать другую ненужную информацию вместе со списком, просто проанализируйте возвращенный текст на наличие открывающей и закрывающей скобки, внутри которой будут доступны все галочки. Просто добавьте этот список во фрейм данных статьи (вы можете увидеть код для этого в подходе токенизации).

Подход к токенизации

Для этого подхода нам нужно будет собрать базу данных всех тиков. Есть много источников, таких как Nasdaq, где вы можете скачать CSV либо со всеми тикерами, либо с определенными рынками и критериями, если вы хотите искать в определенной нише.

Затем мы будем использовать NLTK для токенизации данных и поиска конкретных упоминаний этих тикеров в статьях.

# Tokenize page source
tokens = nltk.word_tokenize(pageSource)

# Return all mentions of tickers in page source
tickMentioned = []
for token in tokens:
    if token in tickList:#Tick List is a list of all publicly traded stocks
        tickMentioned.append(token)

# Remove duplicates
tickMentioned = list(set(tickMentioned))
print(tickMentioned)

# Add tickers mentioned to newsdf
newsdf["Tickers Mentioned"][i] = tickMentioned

# Save dataframe to csv
newsdf.to_csv("mentions.csv", index=False)

Примечание. Этот подход больше похож на искусство, чем на точную науку. Многие бегущие строки, такие как «IT», будут отображаться в поиске. Либо удалите эти галочки из списка, либо сделайте результаты чувствительными к регистру, чтобы анализировались только буквы верхнего регистра. Кроме того, у многих организаций есть баннеры, которые показывают, как работают разные компании и их показатели, хотя в статье прямо не говорится, что это акции роста. Они будут повторяться повсюду, поэтому удалите все, что кажется встречающимся в каждой статье конкретной организации. Любые выбросы в любом случае будут проигнорированы, потому что мы будем просматривать много статей.

Создание портфолио

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

Мы видим, что наш набор данных сильно склоняется к Motley Fool. Нам нужно будет посмотреть на прибыль каждой организации, чтобы получить более полное представление о том, как работает каждая организация.

Похоже, это отличный список! Распределение, кажется, имеет смысл, и выбранные тикеры выглядят так, как будто они составляют сильное портфолио.

Теперь ждем месяц и записываем результаты.

Полученные результаты

Портфель был размещен на счете в 100 000 долларов США 2 июня 2023 года, и данные регистрировались в течение следующего месяца до 12 июля 2023 года.

Теперь давайте рассмотрим прибыль, полученную различными организациями. Красная линия представляет собой прибыль SPY (Standard & Poor's 500 Index) за этот период времени, а фиолетовая пунктирная линия иллюстрирует эффективность нашего портфеля. Интересно, что Nasdaq лидирует, имея замечательную прибыль в 15,5%! Однако важно отметить, что у Nasdaq и US News было относительно небольшое количество статей по сравнению с другими источниками, поэтому это может неточно отражать общую производительность обеих соответствующих организаций.

С другой стороны, Investopedia и Yahoo Finance имели более высокий охват статей, а также превзошли не только SPY, но и все источники новостей в целом!

Набор данных содержал большое количество статей от Motley Fool, что делает еще более удивительным, что их прогнозы оказались одними из худших. Поскольку эти статьи находятся в свободном доступе, важно помнить, что эти результаты не обязательно плохо отражают профессиональныерекомендации компании по инвестициям. Однако это заставляет задуматься о надежности авторов, которых они принимают для написания на своей платформе. Мы не можем сделать твердые выводы только из этого исследования, но оно заслуживает дополнительных исследований для будущих исследований.

При изучении прибыли нашего портфеля становится очевидным, что она тесно связана с эффективностью SPY, хотя и в большей степени. Если SPY демонстрирует положительный рост, наш портфель имеет тенденцию опережать его со значительным отрывом, и наоборот. Однако особенно примечательно то, что с 8 июня наш портфель неизменно приносил более высокую общую доходность по сравнению с SPY. По состоянию на 12 июля в доходности появился явный разрыв, что ясно свидетельствует о превосходной эффективности нашего портфеля.

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

Заключительные мысли

Мы создали базовый портфель на основе мнения толпы и получили значительную прибыль в размере 9800 долларов США в течение 40 дней. Хотя эта статистика сама по себе не говорит нам всего, мы видим некоторый потенциал в этой стратегии в будущем.

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

Я не могу выразить, насколько я благодарен всем вам! Я искренне надеюсь, что это было полезно! Если у вас есть какие-либо вопросы, я буду рад ответить на них в разделе комментариев. Кроме того, я открыт для фрилансеров и готов обсудить будущие возможности.