Добро пожаловать во вторую часть моего руководства по использованию JavaScript и Node.js с Alpaca для алгоритмической торговли. Если вы еще не читали первую часть, обязательно посмотрите ее здесь. К концу этой части вы сможете написать очень простой алгоритм, который будет создавать заказы на покупку и продажу в Alpaca на основе двух простых скользящих средних. Полный код этой части руководства можно найти в index.js в моем репозитории GitHub. Если вы предпочитаете видео-версию этого урока, не стесняйтесь проверить мое видео на YouTube.
Справочная информация о простых скользящих средних
Если вы не знакомы со скользящими средними, ознакомьтесь с этой отличной статьей, доступной на Investopedia. По сути, мы рассмотрим две скользящие средние по ценам закрытия минут за два разных периода: последние 20 минут и последние 50 минут. Когда скользящие средние пересекаются, если 20 идет около 50, мы будем считать это сигналом покупки, а если 20 упадет ниже 50, мы будем считать это сигналом продажи. Это не лучший алгоритм для торговли, но он послужит доказательством концепции написания реальных торговых алгоритмов.
Установить lodash и технические индикаторы
Если вы раньше программировали на JavaScript, велика вероятность, что вы использовали lodash. Он предоставляет несколько чрезвычайно полезных методов, которые упрощают работу с объектами и массивами, поэтому мы будем использовать его в нашей программе. Кроме того, мы будем использовать пакет под названием technicalindicators
, который позволит нам провести быстрый технический анализ, а точнее простые вычисления скользящей средней. Чтобы установить эти пакеты, выполните эти две команды:
npm install --save lodash npm install --save technicalindicators
Как только вы это сделаете, вы должны быть готовы вернуться к коду!
Импортируйте новые пакеты
Затем нам нужно импортировать только что установленные пакеты. Вверху index.js
добавьте эти строки вокруг нашего импорта Альпаки:
const _ = require(‘lodash’); const Alpaca = require(‘@alpacahq/alpaca-trade-api’); const SMA = require(‘technicalindicators’).SMA;
Мы получаем lodash как _
и SMA
из пакета технических индикаторов, чтобы мы могли делать некоторые простые скользящие средние.
Удалить printAccount
Затем вы можете продолжить и удалить следующие строки, которые мы использовали только для тестирования нашего подключения к Альпаке:
async function printAccount() { const account = await alpaca.getAccount(); console.log(account); } printAccount();
Добавить переменные
Затем мы инициализируем некоторые переменные, которые мы будем использовать для отслеживания простых скользящих средних и проверки их пересечения. Мы создадим две переменные для отслеживания простых скользящих средних: sma20
и sma50
. Затем мы создадим переменную с именем lastOrder
, которая будет отслеживать, был ли наш последний ордер ордером на покупку или продажу. Нам нужно отслеживать, какой был последний ордер, чтобы мы покупали / продавали только в том случае, если мы фактически пересекаем средние значения, а не просто остаемся выше или ниже. Эта инициализация должна выглядеть примерно так:
let sma20, sma50; let lastOrder = ‘SELL’;
Мы устанавливаем lastOrder
на ‘SELL’
, потому что предполагаем, что у нас нет акций, которыми мы торгуем, и поэтому хотим, чтобы наш первый ордер был ордером на покупку.
Инициализировать простые скользящие средние
Далее мы напишем функцию с именем initializeAverages
. Эта функция установит базовую линию для простых скользящих средних и позволит нам начать торговлю по мере движения цены акций. Первое, что нам нужно сделать в этой функции, - это получить предыдущие столбцы следующим образом:
async function initializeAverages() { const initialData = await alpaca.getBars( ‘1Min’, ‘SPY’, { limit: 50, until: new Date() } ); }
Это даст нам предыдущие 50 одноминутных баров и позволит нам установить среднее значение по последним 20 и 50 ценам закрытия. Итак, поскольку мы берем среднее значение цен закрытия, мы сопоставим полученные бары с массивом цен закрытия:
async function initializeAverages() { const initialData = ... const closeValues = _.map(initialData.SPY, (bar) => bar.c); }
Здесь мы используем lodash, чтобы взять все бары в initialData.SPY
и использовать только число, сохраненное с ключом c
, который является значением закрытия. Это даст нам массив близких значений, которые мы можем использовать сейчас, чтобы установить наши скользящие средние:
async function initializeAverages() { const initialData = ... const closeValues = ... sma20 = new SMA({ period: 20, values: closeValues }); sma50 = new SMA({ period: 50, values: closeValues }); console.log(sma20.getResult()); console.log(sma50.getResult()); } initializeAverages();
Здесь мы используем объект SMA
нашего пакета технических индикаторов для поиска скользящих средних. Когда эти результаты будут напечатаны, вы заметите, что sma20
напечатает 31 скользящее среднее, а sma50
только одно. Это связано с тем, что существует 31 возможный последовательный набор из 20 точек данных, которые дадут нам скользящее среднее, но только один возможный последовательный набор из 50. Итак, теперь у вас должен быть код, который выглядит следующим образом:
async function initializeAverages() { const initialData = await alpaca.getBars( ‘1Min’, ‘SPY’, { limit: 50, until: new Date() } ); const closeValues = _.map(initialData.SPY, (bar) => bar.c); sma20 = new SMA({ period: 20, values: closeValues }); sma50 = new SMA({ period: 50, values: closeValues }); console.log(`sma20: ${sma20.getResult()}`); console.log(`sma50: ${sma50.getResult()}`); } initializeAverages();
Создать клиент Alpaca Websocket
Затем мы создадим клиента, который позволит нам использовать веб-узел Alpaca для отслеживания интересных событий, таких как изменения цен на акции. Сначала мы просто создадим client
переменную и добавим onConnect
функцию:
const client = alpaca.websocket; client.onConnect(() => { client.subscribe([‘AM.SPY’]); setTimeout(() => client.disconnect(), 6000*1000); });
Итак, здесь много чего происходит. Сначала мы создаем клиентскую переменную, которую берем из Альпаки. Затем мы добавляем прослушиватель событий, который происходит всякий раз, когда мы подключаемся к веб-сокету. В этой функции мы можем подписаться на список каналов. В этом случае мы подписываемся на AM.SPY
, что означает прослушивание сводных минутных обновлений для SPY. Это позволит нам получать обновления каждую минуту с полосой на SPY, содержащей значения открытия, закрытия, максимума, минимума, объема и других значений. Наконец, мы устанавливаем тайм-аут в 6000 секунд, который отключит нас от веб-сокета, чтобы мы не оставили это соединение открытым.
Добавить слушателя канала
Далее мы добавим слушателя для минутных обновлений. Мы проанализируем полученные данные и возьмем из них близкое значение:
client.onStockAggMin((subject, data) => { const nextValue = JSON.parse(data)[0].c; });
В этом случае данные вернутся в виде JSON с массивом полос. Поскольку у нас есть только один канал, нам будет важна 0-я запись, и мы снова будем использовать ключ c
для получения значения закрытия. После этого мы можем пересчитать простые скользящие средние:
client.onStockAggMin((subject, data) => { const nextValue = ... const next20 = sma20.nextValue(nextValue); const next50 = sma50.nextValue(nextValue); console.log(`next20: ${next20}`); console.log(`next50: ${next50}`); });
Это позволит получить пересчитанные простые скользящие средние и распечатать их. Теперь мы можем использовать эти пересчитанные простые скользящие средние, чтобы решить, покупать или продавать. Во-первых, мы рассмотрим случай покупки, когда последние 20 скользящих средних пересекают последние 50. Мы можем сделать это с помощью простого оператора if, в котором говорится, что если новые 20 скользящих средних выше 50, и мы не покупали последними, то происходит крест:
client.onStockAggMin((subject, data) => { const nextValue = ... const next20 = ... const next50 = ... if (next20 > next50 && lastOrder !== ‘BUY’) { // Buy! } });
Мы можем использовать противоположную логику, чтобы проверить, пересекаемся ли мы в противоположном направлении:
client.onStockAggMin((subject, data) => { const nextValue = ... const next20 = ... const next50 = ... if (next20 > next50 && lastOrder !== ‘BUY’) { // Buy! } else if (next20 < next50 && lastORder !== ‘SELL’) { // Sell! } });
После этого мы можем передать заказы Альпаке и записать, что произошло. В этом случае я скажу Альпаке купить или продать 300 акций SPY в качестве рыночного ордера, срок действия которого истекает через день. Поскольку на SPY почти наверняка присутствует большой объем, эти заказы следует исполнять быстро. 300 - это несколько произвольно, потому что на моем бумажном счете 100000 долларов, а на создание SPY стоит около 300 долларов. Вот как это будет выглядеть:
client.onStockAggMin((subject, data) => { const nextValue = ... const next20 = ... const next50 = ... if (next20 > next50 && lastOrder !== ‘BUY’) { alpaca.createOrder({ symbol: ‘SPY’, qty: 300, side: ‘buy’, type: ‘market’, time_in_force: ‘day’ }); lastOrder = ‘BUY’; console.log(‘\nBUY\n’); } else if (next20 < next50 && lastOrder !== ‘SELL’) { alpaca.createOrder({ symbol: ‘SPY’, qty: 300, side: ‘sell’, type: ‘market’, time_in_force: ‘day’ }); lastOrder = ‘SELL’; console.log(‘\nSELL\n’); } });
И последнее, но не менее важное: теперь мы должны подключиться к клиенту, который запустит событие прослушивателя onConnect
и подпишет нас на канал, который вызовет обработчик onStockAggMin
. Для этого мы используем эту простую строку:
client.connect();
Резюме
Вот и все! Теперь ваш код должен выглядеть примерно так: Это. Теперь вы можете запустить это с node index.js
и позволить ему работать. В зависимости от того, как движется SPY, вы можете увидеть много или очень мало заказов. Я настоятельно рекомендую вам повозиться с тем, какими акциями вы торгуете, с параметрами, которые влияют на то, покупаете ли вы или продаете, и с количеством, которое вы покупаете или продаете. Это всего лишь простое доказательство того, как мы можем написать очень простой торговый алгоритм. Я надеюсь, что это было полезно, и я с нетерпением жду возможности принести вам больше полезных руководств по мере того, как продолжаю учиться!