Как использовать Python и Ally API для торговли акциями
Пришло время автоматизировать?
Фондовый рынок остается горячим, даже после небольшой коррекции в марте. Согласно исследованию, проведенному SentimenTrader.com, активность розничных трейдеров снизилась с пикового значения в январе. Однако поведение мелких трейдеров (торгует 10 контрактами или меньше) по-прежнему более агрессивно, чем за последние 20 лет.
В последнее время я изучаю, как автоматизировать некоторые из моих стратегий торговли акциями. У одного из брокеров, которые я использую, Ally Financial, есть API, который довольно прост и может использоваться для некоторой алгоритмической торговли. Если вы никогда раньше не использовали Ally, у меня есть краткая шпаргалка, чтобы вы начали получать данные о ценах с помощью API. В этой статье я добавлю к этому шпаргалку и объясню, как собирать новости, а также размещать и отменять заказы на акции с помощью Python.
Управляйте своими ключами API
Ключи API необходимы для взаимодействия с Ally Financial API. Чтобы получить ключи API и разработать с помощью Ally Financial API, следуйте их инструкциям по началу работы здесь:
Если вы новичок в управлении ключами API, обязательно сохраните их в файл или базу данных, а не кодируйте жестко. В этом примере я сохраню свои ключи в файле с именем config.py. Ключи API могут быть очень ценными и должны быть защищены. Если вы обеспокоены утечкой вашего ключа, Ally Financial позволяет вам восстановить новый. Если вы используете файл config.py, a добавьте файл конфигурации в свой файл gitignore, чтобы предотвратить его отправку и в ваше хранилище!
Импортировать зависимости
Для подключения к API используется OAuth1. Можно передать учетные данные как часть URL-адреса при выполнении запроса, но я предпочитаю использовать библиотеку requests_oauthlib.
При необходимости используйте pip install requests-oauthlib.
Обратите внимание, что я использую файл конфигурации для импорта api_key, secret, oath_token, oath_secret. Таким образом, мне не нужно включать эти личные токены в код.
from requests_oauthlib import OAuth1 import requests from config import api_key, secret, oath_token, oath_secret #authentication auth = OAuth1(api_key, secret, oath_token, oath_secret)
Я передаю импортированные токены в OAuth1. Это будет использоваться, когда мы сделаем запрос к API.
Сбор новостей рынка
Сбор новостей рынка может быть полезен для таких действий, как анализ настроений. У Ally Financial API есть две конечные точки API для новостей. Конечная точка поиска используется для поиска идентификаторов статей и возвращает заголовок статьи. Конечная точка новостей позволяет ввести идентификатор статьи и возвращает заголовок и статью. Доступные статьи имеют максимальный возраст 180 дней.
Документация по конечным точкам поиска
Документация по конечным точкам новостей
#the search endpoint v1/market/news/search.json? #the news endpoint. v1/market/news/{article ID}.json
Я создал простую функцию, которая использует конечную точку поиска для сбора идентификаторов статей, а затем использует цикл for для вызова конечной точки новостей с каждым идентификатором, возвращаемым из поиска. Функция возвращает заголовок, идентификатор и историю статьи.
def get_news(sym, maxhits): baseurl = 'https://devapi.invest.ally.com' maxhits = str(maxhits) stories = [] url =f'{baseurl}/v1/market/news/search.json?symbols={sym}&maxhits={maxhits}' response = requests.get(url, auth = auth).json() ids = [response['response']['articles']['article'][n]['id'] for n in range(0, len(response['response']['articles']['article']))] for v in ids: url = f'{baseurl}/v1/market/news/{v}.json' response = requests.get(url, auth = auth).json() stories.append(response['response']['article']) return stories get_news('spy', 5)
Обратите внимание, что функция принимает два параметра: sym и maxhits. Введите тикер акции как символ. Введите максимальное количество результатов, которые вы хотите вернуть, в параметре maxhits. Например, get_news (‘spy’, 5) вернет до 5 статей о биржевом символе SPY.
Создание и отмена приказов на покупку или продажу акций
Для размещения ордеров на покупку, продажу и короткие продажи требуется только одна функция. Это потому, что все заказы публикуются с использованием конечной точки accounts /: id / orders.xml.
Торговая документация Ally API
Документация конечной точки ордеров
При покупке и продаже акций через API информацию о заказе необходимо подавать в формате FIXML. Протокол Financial Information eXchange (FIX) - это бесплатный и открытый стандарт, поддерживаемый тысячами компаний.
FIX стал языком глобальных финансовых рынков, который широко используется фирмами, занимающимися покупкой и продажей, торговыми платформами и даже регулирующими органами для передачи торговой информации.
При вызове API FIXML передается в теле запроса. По сути, это XML. Поскольку для полезных данных запроса требуется FIXML, URI должен использовать формат XML вместо JSON.
URL=f"https://devapi.invest.ally.com/v1/accounts/{acct}/orders.xml"
Ниже приводится пример FIXML для заявки на покупку акций.
<FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2"> <Order TmInForce="1" Typ="2" Side="1" Px="13.39" Acct="60534810"> <Instrmt SecTyp="CS" Sym="GE"/> <OrdQty Qty="1"/> </Order> </FIXML>
Обратите внимание, что в заказе есть несколько атрибутов. Атрибуты соответствуют параметрам заказа, таким как цена, количество и тип заказа. Полный список атрибутов FIXML, используемых с Ally, можно найти в документации.
Функция создания заказа на акции
Чтобы справиться с покупкой акций, создайте функцию, которая принимает переменные для атрибутов FIXML. В FXML необходимо настроить семь атрибутов:
def create_stock_order(sym, typ, side, tif, price, acct, qty):
Sym: символ (тикер) ценной бумаги.
Тип: тип цены. Значения включают Market: 1, Limit: 2, Stop: 3, Stop Limit: 4.
Сторона: Сторона рынка. Ордера на покупку для покрытия приписываются ордерам на покупку со стороной = «1». Значения включают Купить: 1, Продать: 2, Продать: 5.
TmInForce: Time in Force контролирует продолжительность заказа. Значения включают дневной ордер: 0, GTC Order: 1, рыночный при закрытии: 7.
Px: цена ценной бумаги, если она необходима для выбранного Typ. Например, Px потребуется для лимитов (Тип = «2») или стоп-ограничений (Тип = «4»).
Acct: номер вашего счета. Это также необходимо в URL-адресе.
Кол-во: желаемое количество акций или контрактов.
Примечание. Поскольку функция покупает только акции, атрибут SecTyp не нужно настраивать . SecTyp: Тип безопасности. Этот атрибут обязателен. Значения включают обыкновенные акции: CS, Option: OPT.
def create_stock_order(sym, typ, side, tif, price, acct, qty): ''' FIXML KEY Typ: Market: "1" Limit: "2" Stop: "3" Stop Limit: "4" Side: Buy: "1" Sell: "2" Sell Short: "5" tif: Day Order: "0" GTC Order: "1" Market on Close: "7" ''' url=f"https://devapi.invest.ally.com/v1/accounts/{acct}/orders.xml" xmlns = 'xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2"' order = f'TmInForce="{tif}" Typ="{typ}" Side="{side}" Px="{price}" Acct="{acct}"' instrmt = f'SecTyp="CS" Sym="{sym}"' orderQty = f'Qty="{qty}"' payload = f"<FIXML {xmlns}>\r\n <Order {order}>\r\n <Instrmt {instrmt}/>\r\n <OrdQty {orderQty}/>\r\n </Order> \r\n </FIXML>" headers = { 'TKI_OVERRIDE': 'true', 'Content-Type': 'application/xml', } response = requests.post(url,auth = auth, headers=headers, data = payload) f = xmltodict.parse(response.text.encode('utf8'))['response']['clientorderid'] #orderids.append(f) return f
Важно понимать, что эта функция разместит живой заказ. БУДЬТЕ ОСТОРОЖНЫ! Например, если бы я хотел купить 1 акцию GE за 1 доллар, функция выглядела бы так:
create_stock_order("GE", 2, 1,1, "1.00", 123456789, 1)
Функция возвращает Client OrderID. Поскольку запрос отправляется в формате XML, ответ возвращается в формате XML. Для анализа XML-ответа я использую библиотеку xmltodict. Это делает работу с XML более похожей на работу с JSON.
При необходимости используйте pip для установки библиотеки.
pip install xmltodict
Чтобы отслеживать идентификаторы заказов, добавьте их в список или сохраните в базе данных. Чтобы убедиться, что заказ был выполнен, вы можете проверить раздел Статус заказов на панели инструментов союзника. Или используйте конечную точку accounts /: id / orders API.
Отмена заказов
Подобно созданию заказов, отмена заказов также выполняется с помощью FIXML.
<FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
<OrdCxlReq TmInForce="0" Typ="2" Side="1" OrigID="SVI-12345678" Acct="12345678">
<Instrmt SecTyp="CS" Sym="F"/>
<OrdQty Qty="1"/>
</OrdCxlReq>
</FIXML>
Обратите внимание, что в полезной нагрузке указано OrdCxlReq вместо Order. Вместо цены передайте идентификатор заказа в атрибут OrigID.
def can_stock_order(sym, typ, side, tif, acct, qty, orderids): ''' FIXML KEY Typ: Market: "1" Limit: "2" Stop: "3" Stop Limit: "4" Side: Buy: "1" Sell: "2" Sell Short: "5" ‐ tif: Day Order: "0" GTC Order: "1" Market on Close: "7" ''' url = f"https://devapi.invest.ally.com/v1/accounts/{acct}/orders.xml" xmlns = 'xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2"' order = f'TmInForce="{tif}" Typ="{typ}" Side="{side}" OrigID="{orderids}" Acct="{acct}"' instrmt = f'SecTyp="CS" Sym="{sym}"' orderQty = f'Qty="{qty}"' payload = f"<FIXML {xmlns}>\r\n <OrdCxlReq {order}>\r\n <Instrmt {instrmt}/>\r\n <OrdQty {orderQty}/>\r\n </OrdCxlReq> \r\n </FIXML>" headers = { 'TKI_OVERRIDE': 'true', 'Content-Type': 'application/xml', } response = requests.post(url,auth = auth, headers=headers, data = payload) f = xmltodict.parse(response.text.encode('utf8'))['response'] return f
Функции «Создать заказ» и «Отменить заказ» практически идентичны. Функция возвращает словарь, содержащий информацию об успешности отмены заказа. Использовать функцию очень просто:
can_stock_order("GE", 2, 1,1, 123456789, 1, 'SVI-123456789')
Полный код
Я добавил эти функции в свою оригинальную Шпаргалку по Ally API, доступную на Github.com. Теперь вы готовы собирать рыночные котировки, выполнять заказы и искать новости рынка с помощью Ally API! С лучшим пониманием того, как создавать и отменять ордера, легче перейти к таким вещам, как алгоритмическая торговля.
Спасибо!
- Если вам понравилась моя работа, подписывайтесь на меня на Medium, чтобы узнать больше!
- Получите ПОЛНЫЙ ДОСТУП и помогите поддержать мой контент, подписавшись!
- Давайте подключимся к LinkedIn
- Анализировать данные с помощью Python? Загляните на мой сайт!