Как написать бота для биржи криптовалют

Простой бот для торговли на криптобирже

Время на прочтение
8 мин

Количество просмотров 85K

Всем привет! Сегодня мы напишем своего первого боевого торгового робота для игры на бирже. Криптобирже. Почему криптобирже?

а) хайповая тема;
б) у них как-то все попроще.

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

Во-вторых, Вы заработаете. Просто немного.

К/ф «Игра на понижение» (2015 г.)

— Этот запах, что это? Чем пахнет?
— Одеколоном?
— Нет…
— Возможностями?
— Нет. Деньгами.
— Оу….всё ясно
— Запах денег!
— Понятно.

Для самых нетерпеливых, весь код на гитхабе exmo-exchange-trade-bot.

Этап №1: Биржа.

Торговать мы будем на бирже EXMO. Причин несколько. Биржа популярна на просторах СНГ, она русскоязычная и поддерживает ввод рублей, имеет возможность создания пар к рублю.

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

Для нас главное, что она имеет готовые решения для работы с их API. Это безусловно облегчит нашу работу.

Итак, приступим.

Разумеется, на бирже нужно зарегистрироваться и внести немного денег. Я для примера внес 5$.

Далее в личном кабинете Вы получите ключи для доступа к API.

Я буду использовать клиент для NodeJS (поэтому потребуется установить nodejs и npm).

На своем компьютере создаем новую папку и файлом, в котором будет наш торговый робот (напр. exmo/index.js), открываем консоль и делаем последние стандартные приготовления.

Переходим в папку с нашим проектом и пишем — npm init, далее на все вопросы нажимаем клавишу enter.

Далее пишем

npm install exmo-api

Пока пакеты устанавливаются, создадим еще один файлик, назовем его exmo.js и наполним вот этим содержимым.

вот этим содержимым

var CryptoJS = require("crypto-js")
    http = require('http'),
    querystring = require('querystring'),
    request = require('request'),
    config = {
        url: 'https://api.exmo.me/v1/'
    };

function sign(message){
    return CryptoJS.HmacSHA512(message, config.secret).toString(CryptoJS.enc.hex);
}

exports.init_exmo = function (cfg) {
    config.key = cfg.key;
    config.secret = cfg.secret;
    config.nonce = Math.floor(new Date().getTime()*1000);
};

exports.api_query = function(method_name, data, callback){
    data.nonce = config.nonce++;
    var post_data = querystring.stringify(data);

    var options = {
      url: config.url + method_name,
      method: 'POST',
      headers: {
        'Key': config.key,
        'Sign': sign(post_data)
      },
      form:data
    };

    request(options, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            callback(body);
        }else{
            callback(error);
        }
    });
};

exports.api_query2 = function(method_name, data, callback){
    data.nonce = config.nonce++;
    var post_data = querystring.stringify(data);

    var post_options = {
        host: 'api.exmo.me',
        port: '80',
        path: '/v1/' + method_name,
        method: 'POST',
        headers: {
            'Key': config.key,
            'Sign': sign(post_data),
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': Buffer.byteLength(post_data)
        }
    };
    var post_req = http.request(post_options, function(res) {
      res.setEncoding('utf8');
      res.on('data', function (chunk) {
          callback(chunk);
      });
    });

    post_req.write(post_data);
    post_req.end();
};

exports.test = function(){
    return config.key;
};

Этот фаил содержит адрес API, подключение дополнительных библиотек, которые нам нужны для работы с API и основную функцию для запросов к API.

Всё, мы все подготовили и теперь можем непосредственно приступить к созданию персональной «машины по зарабатыванию денег» ;)

Этап №2: Код

Открываем наш index.js и подключим фаил exmo.js:

const exmo = require("./exmo");

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

const apiKey = ‘ВАШ ключ’;
const apiSecret = ‘Ваш секрет’;

Теперь создадим две переменные:
currency1 — это ЧТО покупаем;
currency2 — валюта, за которую покупаем.

Я хочу купить биткоины за доллары:

const currency1 = 'BTC';
const currency2 = 'USD';

Далее важный момент — мы создаем переменную с минимальной суммой ставки. Меньше этого количества биржа купить не позволяет.

Идем по адресу https://api.exmo.com/v1/pair_settings/ ищем свою пару (для меня это BTC_USD) и смотрим первый параметр — min_quantity — 0.001

const currency1MinQuantity = 0.001; 

И ещё немного переменных:

количество минут, через которое неисполненный ордер на покупку будет отменен currency1

const orderLifeTime = 3;

биржевая комиссия (0.002 = 0.2%)

const stockFee = 0.002;

период времени (в минутах) для вычисления средней цены (это понадобится для нашего алгоритма)

const avgPricePeriod = 1;

количество currency2 для покупки currency1 при единоразовой сделки (я закинул 5$ — ими и буду оперировать)

const canSpend = 5;

желаемое количество прибыли с каждой сделки (0.001 = 0.1%)

const profit = 0.001;

Если расходится время биржи с текущим

const stockTimeOffset = 0;

Для удобства объединяем нашу пару через _

let currentPair = currency1+'_'+currency2;

Инициализируем подключение.

exmo.init_exmo({key:apiKey, secret:apiSecret});

Для теста можете запросить информацию о себе:

exmo.api_query("user_info", { }, result => console.log(result););

Переходим в консоль и запускаем

node index.js

Если все сделано верно, то Вы увидите информацию по Вам!

Все работает и можно переходит к самому интересному — функции, которая будет генерировать нам бабки.

Итак, я выше уже говорил что наш алгоритм будет тупым, сейчас Вы поймете на сколько)

Весь фокус состоит в том, чтобы взять историю завершенных сделок за какой-либо период — у нас за это отвечает переменная avgPricePeriod — и посчитать среднюю цену, за которую была продана currency1. За эту среднюю цену мы и выставим свой ордер.

Итак, приступим. Пишем нашу функцию trade()

function trade(){}

Сначала получим список наших открытых ордеров:

1) проверяем есть ли у нас открытые ордера по нашей паре с помощью api-метода user_open_orders. Если есть и они на продажу,

то мы просто ждем, когда они исполнятся ( иногда до скончания веков). Если есть ордера на покупку, просто их запоминаем.

exmo.api_query("user_open_orders", { }, result => {

    let res = JSON.parse(result);

    if(res[currentPair] == undefined) console.log('Открытых оредеров нет');

    let buyOrders = [];

    for(let i in res[currentPair]){
        console.log(res[currentPair][i]);
        if(res[currentPair][i].type == 'sell'){
           console.log('Выход, ждем пока не исполнятся/закроются все ордера на продажу');
        }else{
          buyOrders.push(res[currentPair][i]);
        }
    }

2) Проверяем, если у нас есть открытые ордера на покупку.

Перебираем все ордера и получаем историю по ним с помощью метода order_trades, передав туда id ордера.

Здесь может быть 3 варианта:

if(buyOrders.length > 0){ 
    for(let key in buyOrders){
        console.log('Проверяем, что происходит с отложенным ордером', buyOrders[key]['order_id']);

        exmo.api_query('order_trades', {"order_id": buyOrders[key]['order_id']}, result => {
            let res = JSON.parse(result);

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

if(res.result !== false){
     console.log('Выход, продолжаем надеяться докупить валюту по тому курсу, по которому уже купили часть');
}

2) при втором варианте нам нужно проверить не слишком ли долго висит наш ордер. Цены меняются быстро и, возможно, средняя цена уже не актуальна. Для этого мы завели переменную orderLifeTime, где указываем, сколько наш ордер должен висеть в минутах.

Если время вышло, то отменяем ордер с помощью метода order_cancel, передав ему id ордера.

let timePassed = (new Date().getTime() / 1000) + stockTimeOffset * 60 * 60 - (buyOrders[key]['created']);
if(timePassed > orderLifeTime * 60){
    exmo.api_query('order_cancel',{"order_id":buyOrders[key]['order_id']}, res => {
        let result = JSON.parse(res);
        if(result.error) console.log(result.error);

    console.log(`Отменяем ордер за ${orderLifeTime} минут не удалось купить ${currency1}`);
                    });
        }else{

3) если время ещё не вышло, то мы просто надеемся, что сможем купить по нашей цене.

console.log(`Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло ${timePassed} секунд`);
                }
            }
          });
        }
    }else{

Все, с открытыми ордерами мы разобрались, теперь наш робот знает, что делать с ордерами когда их создаст. Половина дела сделано.

Итак, блок если у нас нет ордеров.

Получаем информацию по нашему аккаунту с помощью метода user_info:

exmo.api_query('user_info',{},(result)=>{
     let res = JSON.parse(result);

Для удобства запишем балансы по нашим парам:

let balance = res.balances[currency1];
let balance2 = res.balances[currency2];

Проверим, есть ли currency1, которую можно продать?

if(balance >= currency1MinQuantity){}

Если да, нам нужно высчитать курс продажи.

Нужно продать всю валюту, которую купили, на сумму которую купили плюс прибыль за вычетом комиссии биржи.

Важный момент! Валюты у нас меньше, чем купили — биржа взяла комиссию.

let wannaGet = canSpend + canSpend * (stockFee+profit);
console.log('sell', balance, wannaGet, (wannaGet/balance));

При создании ордеров, методу order_create нужно передать параметры:

  • pair — это наша актуальная пара для торговли;
  • quantity — количество;
  • price — цена;
  • type — типа создаваемого ордера (buy/sell);

Мы хотим продать — в типе указываем sell.

let options = {
    "pair": currentPair,
    "quantity": balance,
    "price": wannaGet / balance,
    "type": 'sell'
};

и отправляем запрос, если все верно, то Вы увидите запись «Создан ордер на продажу»

exmo.api_query("order_create", options,(result)=>{
     if(result.error) console.log(result.error);

     console.log("Создан ордер на продажу", currency1, result.order_id);
});

Здесь все. Если у нас была валюта, мы просто создали ордер на его продажу.

Теперь переходим к самому интересному блоку: случай, если у нас нет currency1(btc) и мы хотим ее купить за нашу currency2 (usd).

Для начала проверим, достаточно ли денег на балансе в валюте currency2.

if(balance2 >= canSpend){}

Если есть, то нам нужно получить среднюю цену, за которую продают currency1(btc) за промежуток времени, который мы указали в avgPricePeriod.

Немного лирики:
У Exmo есть метод ticker со статистикой и объемами торгов по валютным парам. В статистике указана средняя цена за последние 24 часа. Однако разница средней цены и той, по которой идут торги сейчас может очень отличатся.

Из за этого мы можем долго ждать, когда исполниться ордер на продажу.

Мы сделаем свой велосипед.

У Exmo есть метод trades, он возвращает список сделок по валютной паре.

Мы возьмем совершенные сделки за интересующий нас avgPricePeriod и из них посчитаем среднюю цену.

Это не идеальный вариант, но он покажет реальные цены, по которым продают и покупают.

Например, на момент написания статьи средняя цена BTC_USD — 8314, при этом покупка на бирже осуществляется по цене 7970.

Если мы выставим ордер по средней цене, он сразу же исполнится по минимальной цене, значащейся в ордерах на продажу.

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

Итак, обратимся к методу trades и запросим у него статистику по нашей паре currentPair:

exmo.api_query("trades",{"pair":currentPair}, result => {

    let res = JSON.parse(result);
    let prices = [];
    let summ = 0;

Переберем все результаты и оставим только те, которые подходят к нашему временному периоду.

for(deal in res[currentPair]){
    let timePassed = (new Date().getTime() / 1000) + stockTimeOffset * 60 * 60 - res[currentPair][deal].date;

     if(timePassed < avgPricePeriod * 60){
         summ += parseInt(res[currentPair][deal].price);
         prices.push(parseInt(res[currentPair][deal].price));
     }
}

И посчитаем среднюю цену.

let avgPrice = summ2 / prices.length;

Средняя цена у нас есть, но нам нужно ее немного подправить — вычесть комиссию биржи stockFee и добавить желаемый профит. Таким образом, получив цену ниже средней цены рынка, мы купим чуть больше валюты, так как биржа впоследствии забирает ее часть;

let needPrice = avgPrice - avgPrice * (stockFee + profit);

Получаем конечное количество, которое нам нужно купить.

let ammount = canSpend / needPrice;
console.log('Buy', ammount, needPrice);

Проверяем можно ли купить такое количество валюты (не нарушается ли минимальная сумма покупки).

if(ammount >= currency1MinQuantity){}

Если наше количество больше, то формируем параметры для метода order_create, только на этот раз уже с типом buy.

 let options = {
    "pair": currentPair,
    "quantity": ammount,
    "price": needPrice,
    **"type": 'buy'**
};

exmo.api_query('order_create', options, res => {
    let result = JSON.parse(res);
    if(result.error) console.log(result.error);
        console.log('Создан ордер на покупку', result.order_id);
    });

}else{
    console.log('Выход, не хватает денег на создание ордера');
}

});
}else{
    console.log('Выход, не хватает денег');
}

Теперь нужно поставить нашу функцию на таймер (диапазон — раз в 5 секунду, например) и можем запускать.

var timerId = setTimeout(function tick() {
  trade();
  timerId = setTimeout(tick, 5000);
}, 5000);

node index.js

Поздравляю, Вы написали своего первого торгового робота: можете допиливать алгоритм и зарабатывать кучу денег) шучу.

Думаю у вас возник резонный вопрос «Сколько же денег так можно заработать?»

За одну операцию с 5$ я зарабатываю примерно 2-3 цента. Это связано с примитивностью алгоритма, который работает в случае, если цена колеблется в определенном диапазоне (а это почти всегда не так на криптобиржах). За сутки происходит порядка 10-20 операций (при хороших раскладах). Посчитать можете сами;)

Но мы же не ради денег код мастерим)

Ещё раз ссылка на гитхаб с полной версией бота и комментариями.
https://github.com/v-florinskiy/exmo-exchange-trade-bot

Эта моя первая статья — не судите строго)

Всем профита.

P.S.: Для тех, кто не работал с node, ваш скрипт естественно будет работать, пока отрыта консоль.

Чтобы ваш робот работал 24/7, вам нужен какой-нибудь vps: там вы ставите nodejs, npm и, например, pm2. С помощью этой утилиты скрипт продолжит работу, даже если консоль закрыта.

Прежде всего, давайте определимся с основным термином этой статьи. Что такое торговый бот? Торговый бот — это использование компьютерной программы или системы для торговли на рынке в соответствии с заранее определенным и указанным набором правил. Другими словами, трейдер строит определенный алгоритм для своей торговой стратегии, который будет автоматически выполняться на рынке при выполнении всех условий. Это также причина, почему мы также будем использовать термин алгоритмическая торговля.

Такой стиль торговли идеально сочетается с рынками криптовалюты, что дает ряд преимуществ для алгоритмических трейдеров. Прежде всего — волатильность, рынки криптовалюты обычно имеют гораздо более высокую волатильность, чем традиционные рынки, создавая большие колебания цен и возможностей для трейдеров. Во-вторых, круглосуточная торговая сессия, так как рынки криптовалют открыты для бизнеса 24/7. В-третьих, общая рыночная капитализация, которая меньше по сравнению с традиционными рынками. На традиционных рынках преобладают крупные многомиллиардные фонды, в то время как рынки криптовалют гораздо моложе, что означает, что он относительно менее насыщен крупными фондами и, как следствие, не требует большого капитала, чтобы начать зарабатывать на криптовалюте.

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

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

3 наиболее популярных крипто-торговых стратегий: Создание рынка (Market Making), Арбитраж, Стратегии следования за трендом.

Создание рынка (Market Making)

Это стратегия, в которой происходит непрерывная покупка и продажа, для того чтобы отразить разницу между ценой покупки и продажи. Чтобы сделать это, трейдер должен разместить лимитные ордера по обе стороны от книги заявок (order book), чтобы получить прибыль от спреда (spread). Тем не менее, эта стратегия будет иметь свои ограничения в условиях низкой ликвидности или во время предыдущей экстремальной конкуренции.

Арбитраж

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

Стратегия следования за трендом

Целью этой стратегии является выявление тренда актива и выполнение сделок на основе базового тренда. Стратегия следования за трендом пытается получить прибыль путем анализа импульса актива в заданном направлении. Трейдеры, которые выполняют эту стратегию, войдут в длинную позицию, когда криптовалюта торгуется вверх (long position), и продают позицию (short position), когда тренд разворачивается.

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

Простой торговый бота с использованием TradingView

А пока давайте приведем пример торгового бота, который может быть построен с использованием TradingView (TV). Прежде всего, важно создать сценарий стратегии, потому что сценарий стратегии может быть протестирован, и TV предоставит подробные результаты вашей стратегии.

Код ниже, представляет простую стратегию EMA (exponential moving average), в которой вход и выход происходят при пересечении быстрой и медленной экспоненциальной скользящей средней (EMA). Это можно вставить в Pine Editor TV.

Пример торговой стратегии

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Wunderbit Trading (WBT)

//@version=4
strategy(«EMA cross», overlay=true)

//Inputs
fast_ema=ema(close, 9)
slow_ema=ema(close, 21)

plot(fast_ema, color=color.red)
plot(slow_ema, color=color.blue)

//Strategy Conditions
entry_long = crossover(fast_ema, slow_ema)
exit_long = crossunder(fast_ema, slow_ema)

entry_short= crossover(slow_ema, fast_ema)
exit_short= crossunder(slow_ema, fast_ema)

//Strategy Execution
strategy.entry(«Long», long=true, when=entry_long)
strategy.close(«Long», when=exit_long)

strategy.entry(«Short», long=false, when=entry_short)
strategy.close(«Short», when=exit_short)

Пример торговой стратегии Kirill Osaulenko

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

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

Пример study сценария с той же стратегией

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Wunderbit Trading (WBT)

//@version=4
study(«EMA cross», overlay=true)

//Inputs
fast_ema=ema(close, 9)
slow_ema=ema(close, 21)

plot(fast_ema, color=color.red)
plot(slow_ema, color=color.blue)

//Strategy Conditions
entry_long = crossover(fast_ema, slow_ema)
exit_long = crossunder(fast_ema, slow_ema)

entry_short= crossover(slow_ema, fast_ema)
exit_short= crossunder(slow_ema, fast_ema)

//Strategy Execution

alertcondition(entry_long, title=»Enter Long»)
alertcondition(exit_long, title=»Exit Long»)
alertcondition(entry_short, title=»Enter Short»)
alertcondition(exit_short, title=»Exit Short»)

plotshape(series=entry_long, text=»Long», style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
plotshape(series=exit_long, text=»EXIT Long»,style=shape.triangledown, location=location.abovebar, color=color.purple, size=size.small)
plotshape(series=entry_short, text=»Short», style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
plotshape(series=exit_short, text=»EXIT Short»,style=shape.triangleup, location=location.belowbar, color=color.purple, size=size.small)

Пример study сценария с той же стратегией Kirill Osaulenko

Теперь вы можете создавать оповещения (alerts) для вашего торгового актива и выбирать условия оповещения и действия.

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

Пошаговое руководство по созданию торгового бота на любом языке программирования +28

Блог компании RUVDS.com, Программирование, Финансы в IT


Рекомендация: подборка платных и бесплатных курсов Java — https://katalog-kursov.ru/

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

Часто можно встретить статьи, которые называются примерно так: «10 проектов, которые нужно реализовать программисту». Часто в списки этих статей входят торговые боты. Я считаю, что разработка торгового бота — это достойное вложение сил. Поэтому я решил уделить некоторое время тому, чтобы написать учебное руководство об этом.

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

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

Я буду демонстрировать примеры, написанные на псевдокоде. Поэтому вы сможете читать это руководство и тут же писать собственного бота на выбранном вами языке программирования.

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

Вы выберете оружие, а я научу вас владеть этим оружием.

Шаг 1. Выбираем оружие

На первом шаге этого руководства вы выберете язык программирования, которым будете пользоваться. Этот вопрос вы должны решить самостоятельно.

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

Шаг 2. Ищем поле битвы

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

Итак, вашим первым шагом будет принятие решения о том, чем именно вы собираетесь торговать (акциями, валютами, криптовалютами), и решения о том, где именно вы будете торговать.

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

Более «традиционными» активами можно торговать только в определённые временные промежутки, и часто — только по будним дням. Рынки акций, например, обычно открыты с 9 утра до 4 вечера и по выходным они не работают. Рынки FOREX, хотя и могут работать круглосуточно, обычно закрыты в выходные.

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

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

  1. У вас должна быть законная возможность торговать на выбранной бирже и работать с предлагаемыми ей торговыми инструментами. Если говорить о криптовалютах, то в некоторых странах торговля ими запрещена. Учитывайте это, выбирая инструменты и биржу.
  2. Биржа должна обладать API, который доступен её клиентам. Нельзя создать торгового бота, который не отправляет запросы к бирже и не получает от неё ответов.

После того, как оказалось, что некая биржа удовлетворяет этим двум основным требованиям, вы можете проанализировать её глубже. Например, оценить размер комиссий, оценить её надёжность и известность, взглянуть на качество документации к её API.

И ещё, что так же важно, как и всё остальное, я порекомендовал бы оценить объём торгов биржи. Биржи с низкими объёмами имеют свойство «отставать» от ценовых движений. На них, кроме того, сложнее бывает выполнять лимитные заявки (подробнее об этом мы поговорим ниже).

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

Шаг 3. Строим лагерь

Если биржа — это поле битвы, то теперь мы поговорим о том месте, из которого будем отправлять на поле битвы свои войска. Кстати, мне, пожалуй, пора завязывать с такими аналогиями.

Здесь я говорю о сервере. Код бота должен выполняться на некоем сервере, что позволит боту отправлять запросы к API биржи.

Во время тестирования бота, естественно, в роли сервера может выступать ваш компьютер. Но если вам нужно, чтобы бот работал бы постоянно, обычный компьютер — это, определённо, не лучший выбор.

Тут у меня есть два предложения:

  1. Роль сервера может выполнять Raspberry Pi (этот подход интереснее).
  2. Сервером может быть некая облачная служба (а этот подход лучше).

Я так думаю, что организация деятельности бота на базе собственного Raspberry Pi-сервера — это интересная и современная идея, поэтому, если и вам эта идея нравится, вы можете претворить её в жизнь.

Но большинство создателей ботов, вероятно, остановят свой выбор на каком-нибудь провайдере облачных услуг вроде AWS, Azure, GCS или Digital Ocean.

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

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

Шаг 4. Создаём бота

А вот теперь начинается самое интересное. Но, прежде чем приступать к этой части нашего проекта, проверьте, выполнено ли следующее:

  1. Вы зарегистрировались на бирже и получили необходимые разрешения на работу с ней.
  2. У вас есть возможность работать с API биржи, у вас имеется ключ API.
  3. Вы выбрали хостинг для бота.

Если эти вопросы решены, это значит, что мы можем двигаться дальше.

?Простейший бот

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

У нашего бота будут некоторые ограничения:

  1. Бот сможет пребывать лишь в одном из двух состояний: BUY (покупка) или SELL (продажа). Он не будет постоянно размещать заявки на покупку или на продажу по разным ценам. Если последней операцией была продажа, то следующей операцией, которую попытается выполнить бот, будет покупка.
  2. Бот будет использовать фиксированные пороговые значения для принятия решений о покупке и продаже. Более интеллектуальный бот может быть способен самостоятельно настраивать подобные значения, основываясь на различных индикаторах, но стратегия и ограничения нашего бота будут задаваться вручную.
  3. Он будет торговать только одной валютной парой. Например — BTC/USD.

Эти ограничения упрощают нашу задачу. Бот будет простым, а значит, его легче будет создать и поддерживать. Это же позволит нам очень быстро развёртывать его код на сервере. В целом, тут мы говорим о принципе KISS.

?Механизм принятия решений

Вот простая диаграмма, дающая общий обзор функционирования нашего бота.

А теперь можно приступать к планированию архитектуры бота.

Нам, для начала, понадобится переменная, в которой будут храниться сведения о том, в каком именно состоянии находится бот в текущий момент. Это либо BUY, либо — SELL. Для хранения подобных сведений хорошо подойдёт логическая переменная или перечисление.

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

Например, если я купил что-то по цене в $100, а в настоящий момент цена составляет $102, то мы имеем дело с увеличением цены на 2%. Если порог для операции SELL установлен на однопроцентное увеличение цены, то бот, увидев эти 2%, продаст актив, так как он уже получил прибыль, превышающую заданное нами пороговое значение.

В нашем случае подобные значения будут константами. Нам понадобится 4 таких значения — по 2 на каждое состояние бота.

?Пороговые значения для выполнения операции BUY (если бот находится в состоянии SELL)

  • DIP_THRESHOLD: бот выполняет операцию покупки в том случае, если цена уменьшилась на значение, большее, чем задано DIP_THRESHOLD. Смысл этого заключается в реализации стратегии «покупай дёшево, продавай дорого». То есть, бот будет пытаться купить актив по заниженной цене, ожидая роста цены и возможности выгодной продажи актива.
  • UPWARD_TREND_THRESHOLD: бот покупает актив в том случае, если цена выросла на значение, превышающее то, что задано этой константой. Этот ход противоречит философии «покупай дёшево, продавай дорого». Его цель заключается в том, чтобы выявить восходящий тренд и не пропустить возможность покупки до ещё большего роста цены.

Вот иллюстрация, которая может помочь в понимании смысла этих констант.

Если мы выполнили операцию SELL в момент, отмеченный на рисунке красным маркером SELL, то после этого бот, принимая решение о выполнении операции BUY, будет руководствоваться пороговыми значениями DIP_THRESHOLD и UPWARD_TREND_THRESHOLD.

Если цена уйдёт ниже нижней зелёной линии или выше верхней зелёной линии, мы выполним операцию BUY. В ситуации, показанной на рисунке, цена ушла выше верхнего предела. Поэтому мы, руководствуясь значением UPWARD_TREND_THRESHOLD, выполнили операцию BUY.

?Пороговые значения для выполнения операции SELL (если бот находится в состоянии BUY)

  • PROFIT_THRESHOLD: бот продаёт актив в том случае, если цена стала выше цены, вычисленной на основе этого значения, так как ранее актив был куплен по более низкой цене. Именно так мы получаем прибыль. Мы продаём актив по цене, которая выше той, что была в момент его покупки.
  • STOP_LOSS_THRESHOLD: в идеальной ситуации мы хотели бы, чтобы бот продавал бы активы только тогда, когда продажа приносит нам прибыль. Но, возможно, произошло сильное движение рынка вниз. В такой ситуации мы решим выйти из сделки до того, как понесём слишком большие убытки, и позже купить актив по более низкой цене. Это пороговое значение используется для закрытия позиции с убытком. Цель этой операции — предотвращение более сильных потерь.

Вот иллюстрация.

Тут показана ситуация, когда там, где стоит маркер BUY, была сделана покупка. После этого цена достигает предела, заданного PROFIT_THRESHOLD, и мы продаём актив с прибылью. Именно так боты зарабатывают.

Теперь, после того, как у нас сформировалось общее понимание того, как функционирует бот, пришло время рассмотреть псевдокод.

?Вспомогательные функции для работы с API

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

FUNCTION getBalances():
    DO: Выполнить GET-запрос к API биржи для получения 
    сведений о балансах
    RETURN: Сведения о балансах

FUNCTION getMarketPrices():
    DO: Выполнить GET-запрос к API биржи для получение 
    текущей цены актива
    RETURN: Текущая цена актива

FUNCTION placeSellOrder():
    DO:
        1. Вычислить количество актива для продажи (на основе
        некоего заданного порогового значения, например, 
        50% общего баланса)
        2. Отправить POST-запрос к API биржи для выполнения
        операции SELL
    RETURN: Цена совершения сделки

FUNCTION placeBuyOrder():
    DO:
        1. Вычислить количество актива для покупки (на основе
        некоего заданного порогового значения, например, 
        50% общего баланса)
        2. Отправить POST-запрос к API биржи для выполнения
        операции BUY
    RETURN: Цена совершения сделки

// Необязательная функция, которая предназначена для 
// получения подтверждения выполнения операций
FUNCTION getOperationDetails():
    DO: Выполнить GET-запрос к API биржи для получения
    сведений об операции
    RETURN: Сведения об операции

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

Часто, например, когда торгуют парой XAU/USD (золото и доллары США), при выполнении запроса можно указать или то, сколько золота нужно купить, или то, сколько долларов нужно продать. При выполнении подобных запросов очень важно чётко понимать смысл производимых действий.

?Главный цикл бота

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

FUNCTION startBot():
    INFINITE LOOP:
        attemptToMakeTrade()
        sleep(30 seconds)

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

bool isNextOperationBuy = True

const UPWARD_TREND_THRESHOLD = 1.50
const DIP_THRESHOLD = -2.25

const PROFIT_THRESHOLD = 1.25
const STOP_LOSS_THRESHOLD = -2.00

float lastOpPrice = 100.00

FUNCTION attemptToMakeTrade():
    float currentPrice = getMarketPrice()
    float percentageDiff = (currentPrice - lastOpPrice)/lastOpPrice*100
    IF isNextOperationBuy:
        tryToBuy(percentageDiff)
    ELSE:
        tryToSell(percentageDiff)

FUNCTION tryToBuy(float percentageDiff):
    IF percentageDiff >= UPWARD_TREND_THRESHOLD OR percentageDiff <= DIP_THRESHOLD:
        lastOpPrice = placeBuyOrder()
        isNextOperationBuy = False

FUNCTION tryToSell(float percentageDiff):
    IF percentageDiff >= PROFIT_THRESHOLD OR percentageDiff <= STOP_LOSS_THRESHOLD:
        lastOpPrice = placeSellOrder()
        isNextOperationBuy = True

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

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

На каждой итерации цикла бот будет проверять своё текущее состояние (BUY или SELL) и будет пытаться выполнить торговую операцию, используя при анализе текущей ситуации жёстко заданные в его коде пороговые значения. Затем, если операция будет выполнена, бот обновит сведения о своём текущем состоянии и данные о цене, по которой была совершена последняя операция.

Шаг 5. Улучшаем бота

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

?Журналы

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

Каждый шаг работы программы должен был сопровождаться примерно такими записями:

[BALANCE] USD Balance = 22.15$
[BUY] Bought 0.002 BTC for 22.15 USD
[PRICE] Last Operation Price updated to 11,171.40 (BTC/USD)
[ERROR] Could not perform SELL operation - Insufficient balance

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

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

FUNCTION createLog(string msg):
    DO:
        1. Вывести msg в терминал
        2. Записать msg в файл журнала, добавив отметку времени

?Идентификация трендов

Главная цель нашего бота заключается в том, чтобы дёшево покупать активы и продавать их, получая прибыль. Но в его коде есть две константы, символизирующие два пороговых значения, которые отчасти этой цели противоречат. Это UPWARD_TREND_THRESHOLD и STOP_LOSS_THRESHOLD.

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

То, как сейчас устроен анализ цены, очень сильно нас ограничивает. Анализ цены, проводимый путём сравнения пары показателей, далёк от механизма, позволяющего выявлять тренды.

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

Нам нужно лишь организовать наблюдение за большим количеством ценовых значений, чем раньше. А раньше мы хранили сведения лишь об одном ценовом показателе — о стоимости актива на момент последней операции (lastOpPrice). Можно, например, хранить сведения о ценах за 10 или 20 последних итераций цикла бота и сравнивать с текущей ценой их, а не только lastOpPrice. Это, вероятно, позволит лучше идентифицировать тренды, так как при таком подходе мы можем уловить краткосрочные колебания цены, а не колебания, происходящие за долгое время.

?База данных?

Простому боту, на самом деле, база данных не нужна. Ведь он оперирует весьма небольшими объёмами данных и хранит всю необходимую ему информацию в памяти.

Но что произойдёт в том случае, если, например, бот будет аварийно остановлен? Как ему узнать, без вмешательства человека, о том, каким было значение lastOpPrice?

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

При таком подходе бот, запускаясь, может не использовать значения, жёстко заданные в коде. Вместо этого он обращается к сохранённым данным и продолжает работу с того места, где она была прервана.

В зависимости от того, насколько простой, по вашему мнению, должна быть эта «база данных», вы можете даже решить использовать в таком качестве обычные .txt- или .json-файлы, так как, в любом случае, речь идёт о хранении весьма ограниченного набора данных.

?Панель управления

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

Это потребует наличия у бота собственного серверного API, предназначенного для управления его функционалом.

Подобный подход, например, позволит легко менять пороговые значения.

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

?Тестирование стратегий на исторических данных

Многие биржи дают клиентам доступ к историческим ценовым данным. Кроме того, если вам нужны такие данные, их обычно несложно достать.

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

?Дополнительные сведения о пороговых значениях и заявках

При размещении заявок нужно учитывать несколько моментов.

Во-первых, нужно знать о том, что существуют два типа заявок: лимитные и рыночные. Если вы совсем ничего об этом не знаете — вам, определённо, стоит почитать специальную литературу. Я тут объясню эти идеи буквально в двух словах.

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

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

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

Кроме того, к таким заявкам обычно применяются более низкие комиссии, чем к рыночным. Это так из-за того, что к рыночным заявкам обычно применимо то, что называется «taker fee» («комиссия получателя»), а к лимитным заявкам — то, что обычно называется «maker fee» («комиссия создателя»).

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

Обратите внимание на то, что бот, который мы тут рассматриваем, лучше всего подходит для работы с рыночными заявками.

И, завершая разговор о комиссиях, хочу отметить, что задавая значение PROFIT_THRESHOLD нужно учитывать и комиссии.

Для того чтобы получить прибыль, бот должен сначала выполнить операцию BUY, а потом — операцию SELL. А это значит, что комиссия будет взята два раза.

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

Поразмыслим об этом, исходя из предположения о применении комиссий, не зависящих от суммы заявки и от вида операции. Итак, комиссия за покупку актива на $100,00 составляет $0,50. Если этот актив будет продан за $100,75 и при этом будет взята такая же комиссия, то окажется, что валовая прибыль составляет 0,75%. Но, на самом деле, тут мы имеем дело с чистым убытком в 0,25%.

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

Итоги

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

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

Я рассказал вам о разработке торговых ботов всё, что хотел. Надеюсь, теперь вы сможете создать собственного бота.

А вы пользуетесь торговыми ботами?

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

Как все начиналось

Утро типичного фрилансера

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

  • в новостях по радио – «биткоин установил новый рекорд за год»;
  • в интернетовских новостных лентах – обсуждение роста цен на новые монеты и много-много тем про ICO;
  • даже на ТВ-каналах нет-нет, да и мелькало что-то про майнинг.

Последний работодатель пропал с письмом о том, что с разработки профильного ПО их команда переключается на программы, связанные с криптовалютами. И даже Топовый блог о хайпах стал не менее Топовым блогом о крипте 🙂

Я на минутку закрыл глаза и дал себе помечтать – чем занялся бы, если бы смог обеспечить себе достаточный пассивный доход. Как распорядился бы временем, которое не будет больше целиком проводиться в работе «на дядю», пусть даже и удаленно. Ради любопытства вбил в поисковик «криптобиржа», и среди прочих новостей взгляд зацепился за строчку о закрытии BTC-e. Еще через несколько минут после пары запросов в гугле я вышел на «наследника» соскамившейся биржи – Wex – и наблюдал размеренные волны «японских свечей» графика. И какой-то неугомонный исследователь внутри шепнул: «Смотри, как это интересно! Попробуй, ты же сможешь!»

Что именно я должен смочь и что вообще делать на бирже, я тогда представлял с трудом, но интерес не отпускал. С нулевыми знаниями финансового анализа и таким же нулевым чутьем я понимал, что торговать вручную – не вариант. Небольшой, но стабильный заработок без нервов и метания «а вот сейчас купить или не купить, продать или не продать?» казался идеальным вариантом. И еще через пару часов раздумий паззл, громко щелкнув, сложился.

Торговые роботы трудятся круглосуточно

Торговый бот! Вот она, мечта каждого ленивого уважающего себя трейдера! Не знающая усталости программа, торгующая на бирже 24 часа в сутки 7 дней в неделю. И, разумеется, постоянно приумножающая депозит.

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

Знакомство с биржей

Еще день или два прошли в изучении биржи и методов работы с ней. Я читал инструкции по инструментам разработчика (API), и, низкий поклон создателям биржи, там же нашел много примеров. Обнаружились готовые коды и на Python, и на PHP, и на С++/C#, и даже наработки для Excel (привет, старый добрый Visual Basic). Через некоторое время я уже мог смотреть на сделанное собственными руками окошко с динамикой курсов покупки и продажи.

Можно вечно смотреть на то, как горит огонь, течет вода и растет в цене биткоин

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

  • получать информацию о текущем балансе;
  • выставлять отложенный ордер на покупку/продажу криптовалюты;
  • просматривать сводку всех своих ордеров или данные конкретного ордера;
  • отменять ордер.

Баланса еще не было. Поняв, что от теории пора переходить к практике, я зарегистрировался на бирже и пополнил счет, переведя с кошелька Advanced Cash оставшиеся после старых забав с хайпами 350 долларов. Еще день или два ушли на то, чтобы разобраться с тем, как получать ключи для торговли, отправлять через программу команды на биржу и как настроить аутентификацию через HTTP-запросы. Поначалу понятного было мало, но примеры чужих кодов, собственное упорство и всезнающий гугл помогли успешно пройти это испытание.

Поверьте – это очень приятное чувство: когда нажимаешь на кнопку в программе, и через секунду видишь в кабинете биржи торговый ордер, созданный автоматически. Начало было положено.

Круговорот валюты

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

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

Я попробовал рассмотреть ситуацию с «механической» позиции. Иными словами, бот торгует криптовалютой полностью самостоятельно, без моего участия. С момента включения и далее постоянно. Что в это время происходит с ценой? Правильно: она может расти или падать.

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

Стоимость ордера решил сделать минимальным для данной биржи – 0,001 BTC, и сразу столкнулся с тем, что продать купленную крипту и получить обратно доллары не получится. Биржа берет комиссию в 0,2% от каждой сделки, поэтому на балансе после исполненного ордера на покупку окажется не 0,001, а 0,00998 BTC. В итоге цену ордера увеличил до 0,0011 BTC. При дальнейшем падении цены бот должен был снова и снова закупать 0,0011 BTC, пока на балансе есть средства для этого, а с приближением баланса к нулю – перестать закупать крипту и ждать исполнения ордеров на продажу. Если баланс пополнится – снова начать закупать. Шаг изменения цены для выставления нового ордера я определил в 10 долларов.

При росте цены бот, соответственно, должен продавать крипту и получать взамен фиат, но уже с определенной прибылью. Прибыль я ограничил 1% от каждой пары сделок (закупка + продажа). Жадничать и стремиться к большей прибыли не стал, так как в этом случае роста курса пришлось бы ждать долго. В то же время и уменьшать прибыль до минимума не имело смысла, так как большую ее часть «съедала» бы двойная комиссия – с покупки крипты и с ее последующей продажи.

Попытка заработать на противостоянии

Алгоритм работы бота для торговли криптовалютой становился все яснее и яснее:

  1. Запросить с биржи текущие цены покупки и продажи биткоина.
  2. Определить «коридор» цен с разбросом в 10$. К примеру, при цене покупки в 6573$ этим «коридором» для бота станет 6570-6580$.
  3. Выставить ордер на покупку 0,0011 BTC по минимальной цене «коридора» – 6570$. Если закупочный ордер по такой цене уже выставлен, ничего не делать (иначе бот будет выставлять ордера на покупку, пока не израсходует весь баланс).
  4. Этот пункт работает при падении цены. Проверить, есть ли на верхней границе «коридора» (6580$) ордер на покупку и исполнен ли он. Если ордер был выставлен ранее и он исполнился, создать ордер на продажу 0,0010978 BTC. Цена продажи при этом рассчитывается ботом автоматически с учетом комиссии биржи (0,2%) и желаемой прибыли (1%). Если ордер на продажу по такой цене уже выставлен, ничего не делать (иначе бот будет спамить ордерами на продажу).
  5. Этот пункт работает при увеличении цены. Проверить, исполнился ли ордер на продажу по самой минимальной из выставленный ботом цен. Если ордер на продажу исполнился, то снова можно выставлять соответствующий ему ордер на закупку.
  6. Повторять пункты с 1 по 5 снова и снова.
  7. PROFIT!

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

В теории все должно было замечательно работать. Заставив мозг хорошенько выложиться, я даже смог обучить бота всем этим премудростям. Время летело незаметно, и от идеи до первой стратегии и до ее реализации в строчках кода прошли уже без малого две недели. Усталость давала о себе знать, но в один прекрасный момент я внезапно осознал: все, бот готов. Мозг молил о передышке, но желание опробовать программу в действии было гораздо сильнее 🙂

Испытание боем

На старт, внимание, марш!

И действительно, что может пойти не так?

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

Ох, как я завидовал в те дни мирно дремавшему рядом кошаку…

Не забросить всю мою затею помогла только появившаяся «спортивная злость». Если уже потратил столько времени на изучение, стратегию, код, так уж доделай все до конца!

И прогресс с каждым днем становился заметнее и заметнее. Программа все реже вылетала с ошибками, а потом я и вовсе мог спокойно спать всю ночь, а бот работал без сбоев. Это была маленькая, но такая ценная победа! При текущих колебаниях курса накапливалось 10-15 ордеров на продажу, но в течение дня, как правило, они все исполнялись. И баланс ежедневно подрастал на доллар-полтора. Через некоторое время я осмелел и увеличил стоимость торгуемых ордеров. Прирост баланса возрос уже до 3-4-5 долларов в день. В абсолютных цифрах, разумеется, это немного. Но в относительных накапливалась неплохая прибыль – 1-1,5% от суммы баланса за сутки.

Конечно, со временем находились и другие, незаметные при начальной отладке программы, «косяки». К примеру, она вылетала с ошибкой при неправильном ответе от сервера биржи (такое случается, когда торги ведутся слишком активно). Или файл со списком ордеров, предназначенный для первоначальной загрузки бота при сбое – при выключении электричества или перезагрузке компьютера – был «криво» пересохранен программой как раз во время выключения электричества. Шанс подобного совпадения – минимален, но оно случилось, и такие случаи тоже нужно учитывать. Спас вовремя сделанный бэкап.

Вплоть до резких колебаний цен и последующего падения при новости об отмене SegWit2x бот торговал прекрасно и чуть менее, чем за 2 недели увеличил баланс моего счета на бирже почти на 15%.

А после я стал «счастливым» обладателем BTC по цене в 7500-7700 долларов. Так ли это плохо? Не думаю. С одной стороны, за время работы бот вывел баланс в полный безубыток, даже если я продам крипту по текущей цене. С другой – я верю, что курс биткоина вернется на прежний уровень и дальше будет расти, и тогда бот продолжит приносить небольшую, но ежедневную прибыль.

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

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

Вместо заключения

Искренне надеюсь, что этот рассказ будет для кого-то полезным.

Текущая версия бота в действии

Он не о том, как можно научиться торговать или программировать… Вовсе нет. Я просто хотел рассказать вам о том, как важно пробовать себя в чем-то новом и не бояться неизвестного, ставить новые цели и не отказываться от старых.

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


Post Views:
2 218

В данной статье мы расскажем вам о том, как создать и настроить вашего первого бота. Данная инструкция поможет вам лучше разобраться в интерфейсе и параметрах настройки. Итак, приступим:
Регистрируемся и логинимся в https://revenuebot.io/, переходим во вкладку «Bots» (https://app.revenuebot.io/office/#/bots/)

Раскрываем меню «CREATE NEW BOT»…

Идентификация, API и кошелек бота

Bot name: Название бота (чаще всего в названии используются характеристики: биржа, торговая пара криптомонет, алгоритм работы и тп.)

Exchange: Выбираем биржу в выпадающем списке (рассмотрим на примере Binance)

Как только вы выберете биржу вам станут доступны следующие поля для заполнения:

Pair: Выбрать торгуемую пару криптомонет. О том, как выбрать эффективную торговую пару подробно написано тут — «Как подобрать эффективную торговую пару криптомонет»

API key: Выбрать API ключ из ранее созданных, либо создать новый.

О том, как создать API ключ подробно написано тут — «Как создать API ключ на бирже Binance и добавить его на RevenueBOT«.

Depo: Выбрать виртуальный кошелек из ранее созданных, либо создать новый, где ввести:

- Название кошелька. Выбирайте название для кошелька такое, чтобы его было легко идентифицировать.
- Комментарий к кошельку для удобства. (Не обязательный параметр).
- Выбрать биржу в выпадающем списке.
- Выбрать криптомонету в выпадающем списке.
- Ввести количество или процент от имеющегося депозита в аккаунте на бирже. Тут можно проверить онлайн баланс нужной монеты на бирже, выбрав нужный API ключ.

Commission: Выбрать вариант комиссии, которая будет применятся биржей. Данная настройка актуальна только для биржи Binance, так как на ней возможна оплата комиссии в третьем токене, который не участвует непосредственно в текущей торговле (BNB токен).

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

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

Алгоритмы работы бота и его настройки

Algo: Выбрать алгоритм работы бота.

Бот использует API интерфейс бирж для выставления ордеров по выбранному алгоритму и отслеживания их выполнения.
На данный момент существует два алгоритма работы бота RevenueBot:

Алгоритм «Long»

Работа бота происходит циклами и основана на принципе покупай дешевле при падении курса (начальная часть цикла) и продай дороже при росте курса (финальная часть цикла). 
Идея заключается в том, что имея определенный депозит, бот покупает не на всю сумму сразу, а частями в моменты падения цены, используя для этого рассчитанную заранее сетку ордеров.
Первый ордер в сетке самый близкий к текущей цене и самый маленький по объему. Каждый последующий ордер объемней (используется система мартингейл) и дешевле. 
Таким образом, при падении цены бот покупает все больше и больше, но за меньшую цену. Это позволяет совершить итоговую прибыльную сделку, продав все купленное по цене гораздо ниже, чем бот начинал покупать.
По выполнению такой сделки получаем прибыль, бот все подсчитывает и начинает новый цикл работы. Профит получается во второй монете торгуемой пары. 
Успешность такой торговли определяется количеством ордеров в сетке, разницей в их весах, расстоянием между друг другом, отступом первого ордера и как глубоко от текущей цены будет отстоять последний ордер в сетке.
Все эти показатели задаются в настройках. Подробно о каждой из настроек изложено в разделе FAQ о создании бота.
Алгоритм «Short»

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

После выбора алгоритма работы бота, пользователю предлагается воспользоваться шаблонами настройки данного алгоритма: Light trade mode, Normal trade mode, Extreme trade mode.

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

Rate cover: Процент перекрытия изменения цены для расчета сетки ордеров. Данная настройка определяет в процентах отступ последнего ордера в сетке ордеров.

First order indent: Отступ в процентах первого ордера в сетке ордеров.

Price rate to use: Выбор рейта на бирже, от которого вести расчет сетки ордеров. Это могут быть рейты buy, sell, average.

Orders matrix, martingale: Сетка ордеров и мартингейл.

Тут задается количество ордеров в сетке и мартингейл (на сколько процентов каждый следующий ордер в сетке будет весомее предыдущего). Кликнув на view orders matrix, Вы сможете увидеть рассчитанную сетку ордеров.

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

Profit coin: Данная настройка доступна только для алгоритма short. Задает в какой из торгуемых монет будет профит.

Cycle up: Бывает, что бот выставил сетку ордеров, а цена ушла в другую сторону. Получается, что нужно ждать пока цена не вернется, а ждать можно долго.

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

Sleep before cancel orders for cycle up: Тут задается задержка в минутах, перед тем как начать отменять текущую сетку ордеров, когда срабатывает настройка Cycle up.

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

Sleep before cycle up after cancel orders: Тут задается задержка в минутах перед выставлением новой сетки после отмены предыдущей сетки ордеров.

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

Sleep after end of cycle: Тут задается задержка в минутах перед тем как начать новый цикл после завершения текущего цикла.

Так же можно задать каждую из этих настроек самостоятельно и сохранить свой шаблон.

Дополнительные настройки

add revenue to depo: При получении прибыли можно добавлять ее к депозиту который использует бот, таким образом увеличивая депозит.
При включенной настройке весь профит от работы бота зачисляется на виртуальный кошелек, который использует данный бот.

logarithmic scale for orders: Обычно сетка ордеров рассчитывается так, что все ордеры в ней расположены линейно, на одинаковом расстоянии друг от друга по всему перекрытию цены.

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

Плотность ордеров можно настроить для разных ситуаций по разному с помощью коэффициента logarithmic factor увеличивая или уменьшая его.
Для большинства случаев подойдет значение logarithmic factor = 1.5.

Кликнув на «view orders matrix», Вы сможете увидеть рассчитанную сетку ордеров.

cost limit: Используйте эту настройку, чтобы не начать покупать слишком дорого и не начать продавать слишком дешево.
Задает максимальную цену, выше которой бот не начнет цикл для алгоритма Long и минимальную цену ниже которой бот не начнет цикл при алгоритме Short.

fix first partial order with profit: Бывает, что первый ордер в сетке частично выполнился, но цена пошла в другую сторону. Такое случается, когда бот оперирует большим депо и ордеры в сетке довольно объемные, даже самый первый.

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

Фильтры для старта бота

Мы рекомендуем всегда настраивать фильтры для старта бота. Они необходимы для того, чтобы бот начал торговлю в самое выгодное время, основываясь на выбранном алгоритме торговли и ваших предпочтениях. Подробнее читайте тут: «Фильтры для старта бота. Описание и настройка.»

Уведомления

Выставляем необходимые уведомления: WEB, E-mail, SMS, Telegram

И нажимаем «Create New Bot».

Поздравляем! Вы создали своего первого бота для биржи!

Теперь, когда мы разобрались, что такое биржа биткоинов, отложенные ордера и API, пришло время написать своего собственного бота.

Тем, кто попал сюда впервые, и не знает о чем идет речь, советую прочитать предыдущие статьи цикла – вы сможете найти перечень внизу этой статьи.

Итак, что это за бот и как он будет работать

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

Бот будет работать на вашем компьютере, подключаться к бирже под вашей учетной записью, все, что вам потребуется – стабильный интернет, наличие некоторой суммы на балансе биржи, ну и установленный интерпретатор Python (о том, как его установить, я писал в этой статье).

Если сделка на покупку не реализуется в течении какого-то времени (у меня это три минуты) бот отменяет ордер и создает новый, с новым курсом.

Если сделка на покупку прошла, то бот создает ордер на продажу, и держит этот ордер до тех пор, пока он не будет целиком исполнен.

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

Бот отслеживает частичное исполнение ордера – он не будет создавать новых ордеров, пока предыдущий не был полностью исполнен или отменен. Если предыдущий ордер был исполнен частично, бот будет ждать завершения всех сделок по этому ордеру.

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

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

Сколько зарабатывает:

В рамках подготовки этой статьи (и отладки алгоритма), я играл на сумму 1 доллар 49 центов – и вот какие он сделки совершал (читать снизу вверх):

Сколько приносит бот на бирже

Если проанализировать доход/расход, то бот принес 3.5 цента за день – при том, что я играл на полтора доллара – это 2.4% со вклада в день.

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

Недостатки бота:

Так как бот учебный, некоторые вещи упрощены и убраны из кода – нет стоп-лоссов и тейк-профитов, курс берется по последним 100 сделкам, которые возвращает эта биржа, и есть вероятность, что бот купит на пике, и потом долго не сможет продать (тут придется либо ждать, либо продать по курсу рынка, выбор за человеком).

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

Так же для упрощения вес не пишется в локальную базу данных, а делается запрос к API. С одной стороны, это хорошо для бота, так как информация всегда приходит актуальная, с другой стороны – плохо, так как эта биржа ограничивает количество API запросов до 180 в минуту. Код, который написан здесь, будет работать без проблем, но если вы запустите параллельно несколько экземпляров бота, с разными валютными парами, например, вполне можете наткнуться на это ограничение.


Реклама



Алгоритм работы:

Для наглядности составлена блок-схема алгоритма работы – полностью транслировать её в текст я смысла не вижу, поясню основные принципы.

Бот играет на сумму которую вы указали – в данном случае для примера выбрана сумма 10 долларов США. На эту сумму бот старается купить биткойнов по курсу, чуть ниже текущего курса рынка. Если в течении некоторого времени (три минуты в примере) купить не получается, этот ордер на покупку отменяется, и создается новый, чуть ниже текущей цены уже на этот момент времени.

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

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

Все, что бот зарабатывает, не тратится – бот играет на указанную сумму, а полученный излишек просто копится на балансе.

Вот блок-схема работы:

алгоритм работы торгового робота


Реклама



Как начать пользоваться:

1. Регистрируйтесь на бирже (если еще этого не сделали):

2. Перейдите в Account-settings-API, нажмите “Generate and save”, и получите ключ и подпись: 

получить API ключи для робота

3. Установите интерпретатор Python 3.4 и выше (описано в этой статье)

4. Создайте файл с названием exmo.py и скопируйте туда код, указанный ниже

5. В коде, в строках 11 и 13, укажите ключи API, полученные в шаге 2

6. В строке  24 укажите сумму, на которую будет играть бот — CAN_SPEND = 1.45 – сейчас указано 1.45 доллара.

7. На балансе не должно быть currency_1 — например, если играете на паре BTC_USD, то BTC заранее переведите в доллары или в другую валюту, а то продаст в минус.

8. Сохраните и запускайте (F5) – бот начнет работать.

Вы можете его запустить, даже если на бирже сейчас нет денег – бот вас предупредит, и просто ничего не купит. Но, конечно, для успешной работы нужно, что бы деньги были :) На 11.04.2017 минимальная сумма на балансе должна составлять примерно 1.5 доллара – это примерно равно минимальной сумме сделки на бирже, 0.001 Btc.


Реклама



Сам код бота:

import urllib, urllib.request, http.client
import time
import json
import sys
# эти модули нужны для генерации подписи API
import hmac, hashlib

# ключи API, которые предоставила exmo
API_KEY = ''
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b''

# Тонкая настройка
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'USD'

CURRENT_PAIR = CURRENCY_1 + '_' + CURRENCY_2




ORDER_LIFE_TIME = 3 # через сколько минут отменять неисполненный ордер на покупку CURRENCY_1
STOCK_FEE = 0.002 # Комиссия, которую берет биржа (0.002 = 0.2%)
AVG_PRICE_PERIOD = 15 # За какой период брать среднюю цену (мин)
CAN_SPEND = 10 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

STOCK_TIME_OFFSET = 0 # Если расходится время биржи с текущим 


# Запросить с биржи лимиты и использовать данные в работе
PAIR_LIMITS = {}
with urllib.request.urlopen("https://api.exmo.com/v1.1/pair_settings") as url:
    pairs_settings = json.loads(url.read().decode())
    if CURRENT_PAIR in pairs_settings:
        PAIR_LIMITS = pairs_settings[CURRENT_PAIR]
    else:
        print("Не удалось найти настройки пары", CURRENT_PAIR, "в ответе от биржи", pairs_settings)
        sys.exit(1)

CURRENCY_1_MIN_QUANTITY = float(PAIR_LIMITS["min_quantity"]) # минимальная сумма ставки - берется из https://api.exmo.com/v1/pair_settings/
PRICE_PRECISION = int(PAIR_LIMITS["price_precision"])

# базовые настройки
API_URL = 'api.exmo.com'
API_VERSION = 'v1'

# Свой класс исключений
class ScriptError(Exception):
    pass
class ScriptQuitCondition(Exception):
    pass




# все обращения к API проходят через эту функцию
def call_api(api_method, http_method="POST", **kwargs):
    # Составляем словарь {ключ:значение} для отправки на биржу
    # пока что в нём {'nonce':123172368123}
    payload = {'nonce': int(round(time.time()*1000))}

    # Если в ф-цию переданы параметры в формате ключ:значение
    if kwargs:
        # добавляем каждый параметр в словарь payload
        # Получится {'nonce':123172368123, 'param1':'val1', 'param2':'val2'}
        payload.update(kwargs)

    # Переводим словарь payload в строку, в формат для отправки через GET/POST и т.п.
    payload =  urllib.parse.urlencode(payload)

    # Из строки payload получаем "подпись", хешируем с помощью секретного ключа API
    # sing - получаемый ключ, который будет отправлен на биржу для проверки
    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
    H.update(payload.encode('utf-8'))
    sign = H.hexdigest()
    
    # Формируем заголовки request для отправки запроса на биржу. 
    # Передается публичный ключ API и подпись, полученная с помощью hmac
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Key":API_KEY,
           "Sign":sign}

    # Создаем подключение к бирже, если в течении 60 сек не удалось подключиться, обрыв соединения
    conn = http.client.HTTPSConnection(API_URL, timeout=60)
    # После установления связи, запрашиваем переданный адрес
    # В заголовке запроса уходят headers, в теле - payload
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
    # Получаем ответ с биржи и читаем его в переменную response
    response = conn.getresponse().read()
    # Закрываем подключение
    conn.close()

    try:
        # Полученный ответ переводим в строку UTF, и пытаемся преобразовать из текста в объект Python
        obj = json.loads(response.decode('utf-8'))

        # Смотрим, есть ли в полученном объекте ключ "error"
        if 'error' in obj and obj['error']:
            # Если есть, выдать ошибку, код дальше выполняться не будет
            raise ScriptError(obj['error'])
        # Вернуть полученный объект как результат работы ф-ции
        return obj
    except ValueError:
        # Если не удалось перевести полученный ответ (вернулся не JSON)
        raise ScriptError('Ошибка анализа возвращаемых данных, получена строка', response)

# Реализация алгоритма
def main_flow():
    
    try:
        # Получаем список активных ордеров
        try:
            opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
        except KeyError:
            if DEBUG:
                print('Открытых ордеров нет')
            opened_orders = []
            
        sell_orders = []
        # Есть ли неисполненные ордера на продажу CURRENCY_1?
        for order in opened_orders:
            if order['type'] == 'sell':
                # Есть неисполненные ордера на продажу CURRENCY_1, выход
                raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
            else:
                # Запоминаем ордера на покупку CURRENCY_1
                sell_orders.append(order)
                
        # Проверяем, есть ли открытые ордера на покупку CURRENCY_1
        if sell_orders: # открытые ордера есть
            for order in sell_orders:
                # Проверяем, есть ли частично исполненные
                if DEBUG:
                    print('Проверяем, что происходит с отложенным ордером', order['order_id'])
                try:
                    order_history = call_api('order_trades', order_id=order['order_id'])
                    # по ордеру уже есть частичное выполнение, выход
                    raise ScriptQuitCondition('Выход, продолжаем надеяться докупить валюту по тому курсу, по которому уже купили часть')
                except ScriptError as e:
                    if 'Error 50304' in str(e):
                        if DEBUG:
                            print('Частично исполненных ордеров нет')
                    
                        time_passed = time.time() + STOCK_TIME_OFFSET*60*60 - int(order['created'])

                        if time_passed > ORDER_LIFE_TIME * 60:
                            # Ордер уже давно висит, никому не нужен, отменяем
                            call_api('order_cancel', order_id=order['order_id'])
                            raise ScriptQuitCondition('Отменяем ордер -за ' + str(ORDER_LIFE_TIME) + ' минут не удалось купить '+ str(CURRENCY_1))
                        else:
                            raise ScriptQuitCondition('Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло %s секунд' % str(time_passed))
                    else:
                        raise ScriptQuitCondition(str(e))

        else: # Открытых ордеров нет
            balances = call_api('user_info')['balances']
            if float(balances[CURRENCY_1]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать?
                """
                    Высчитываем курс для продажи.
                    Нам надо продать всю валюту, которую купили, на сумму, за которую купили + немного навара и минус комиссия биржи
                    При этом важный момент, что валюты у нас меньше, чем купили - бирже ушла комиссия
                    0.00134345 1.5045
                """
                wanna_get = CAN_SPEND + CAN_SPEND * (STOCK_FEE+PROFIT_MARKUP)  # сколько хотим получить за наше кол-во
                print('sell', balances[CURRENCY_1], wanna_get, (wanna_get/float(balances[CURRENCY_1])))
                new_order = call_api(
                    'order_create',
                    pair=CURRENT_PAIR,
                    quantity = balances[CURRENCY_1],
                    price= "{price:0.{prec}f}".format(prec=PRICE_PRECISION, price=wanna_get/float(balances[CURRENCY_1])),
                    type='sell'
                )
                print(new_order)
                if DEBUG:
                    print('Создан ордер на продажу', CURRENCY_1, new_order['order_id'])
            else:
                # CURRENCY_1 нет, надо докупить
                # Достаточно ли денег на балансе в валюте CURRENCY_2 (Баланс >= CAN_SPEND)
                if float(balances[CURRENCY_2]) >= CAN_SPEND:
                    # Узнать среднюю цену за AVG_PRICE_PERIOD, по которой продают CURRENCY_1
                    """
                     Exmo не предоставляет такого метода в API, но предоставляет другие, к которым можно попробовать привязаться.
                     У них есть метод required_total, который позволяет подсчитать курс, но,
                         во-первых, похоже он берет текущую рыночную цену (а мне нужна в динамике), а
                         во-вторых алгоритм расчета скрыт и может измениться в любой момент.
                     Сейчас я вижу два пути - либо смотреть текущие открытые ордера, либо последние совершенные сделки.
                     Оба варианта мне не слишком нравятся, но завершенные сделки покажут реальные цены по которым продавали/покупали,
                     а открытые ордера покажут цены, по которым только собираются продать/купить - т.е. завышенные и заниженные.
                     Так что берем информацию из завершенных сделок.
                    """
                    deals = call_api('trades', pair=CURRENT_PAIR)
                    prices = []
                    for deal in deals[CURRENT_PAIR]:
                        time_passed = time.time() + STOCK_TIME_OFFSET*60*60 - int(deal['date'])
                        if time_passed < AVG_PRICE_PERIOD*60:
                            prices.append(float(deal['price']))
                    try:        
                        avg_price = sum(prices)/len(prices)
                        """
                            Посчитать, сколько валюты CURRENCY_1 можно купить.
                            На сумму CAN_SPEND за минусом STOCK_FEE, и с учетом PROFIT_MARKUP
                            ( = ниже средней цены рынка, с учетом комиссии и желаемого профита)
                        """
                        # купить больше, потому что биржа потом заберет кусок
                        my_need_price = avg_price - avg_price * (STOCK_FEE+PROFIT_MARKUP) 
                        my_amount = CAN_SPEND/my_need_price
                        
                        print('buy', my_amount, my_need_price)
                        
                        # Допускается ли покупка такого кол-ва валюты (т.е. не нарушается минимальная сумма сделки)
                        if my_amount >= CURRENCY_1_MIN_QUANTITY:
                            new_order = call_api(
                                'order_create',
                                pair=CURRENT_PAIR,
                                quantity = my_amount,
                                price="{price:0.{prec}f}".format(prec=PRICE_PRECISION, price=my_need_price),
                                type='buy'
                            )
                            print(new_order)
                            if DEBUG:
                                print('Создан ордер на покупку', new_order['order_id'])
                            
                        else: # мы можем купить слишком мало на нашу сумму
                            raise ScriptQuitCondition('Выход, сумма для торгов (CAN_SPEND) меньше минимально разрешенной биржей')
                    except ZeroDivisionError:
                        print('Не удается вычислить среднюю цену', prices)
                else:
                    raise ScriptQuitCondition('Выход, не хватает денег')
        
    except ScriptError as e:
        print(e)
    except ScriptQuitCondition as e:
        if DEBUG:
            print(e)
        pass
    except Exception as e:
        print("!!!!",e)


try:
    balances = call_api('user_info')['balances']
    alt_balance = float(balances[CURRENCY_1])

    poss_profit = (CAN_SPEND*(1+STOCK_FEE) + CAN_SPEND * PROFIT_MARKUP) / (1 - STOCK_FEE) 

    if float(balances[CURRENCY_1]) > 0:
        decision = input("""
            У вас на балансе есть {amount:0.8f} {curr1}
            Вы действительно хотите, что бы бот продал все это по курсу {rate:0.8f}, выручив {wanna_get:0.8f} {curr2}?
            Введите Д/Y или Н/N
        """.format(
            amount=alt_balance,
            curr1=CURRENCY_1,
            curr2=CURRENCY_2,
            wanna_get=poss_profit,
            rate=poss_profit/alt_balance
        ))
        if decision in ('N','n','Н','н'):
            print("Тогда избавьтесь от {curr} (как вариант создайте ордер с ними по другой паре) и перезапустите бота".format(curr=CURRENCY_1))
            sys.exit(0)
except Exception as e:
    print(str(e))

while(True):
    main_flow()
    time.sleep(1)

Примечания по коду:

Строки 16 и 17  обозначают валютную пару. В данном примере это BTC_USD, но вы можете поменять на любую другую.

Строка 19  — CURRENCY_1_MIN_QUANTITY = 0.001. Это минимальная ставка, которая допускается на бирже. Для разных валют она разная, и, вообще, стоило бы получать её автоматически через API запрос. Но это усложнит код, поэтому я указал её как константу. Тем не менее, если вы планируете торговать другой валютой, вам следует поменять это значение, иначе торговля может затрудниться.

Строка 21 — ORDER_LIFE_TIME = 3. Если ордер на покупку не сыграл, то через сколько минут отменить его и создать новый, с новой ценой, более приближенной к текущим реалиям.

Строка 22 — STOCK_FEE = 0.002. Комиссия биржи за совершенную сделку. Непохоже, что бы она когда-то менялась, но, тем не менее, вы, при необходимости, сможете поменять её здесь если понадобится.

Строка 23 — AVG_PRICE_PERIOD = 90. Бот, в идеале, смотрит сделки за последние 90 минут, что бы узнать среднюю цену, в данной реализации он получает список совершенных сделок, и берет те из них, кто моложе 90 минут. Другой вопрос, что биржа не возвращает больше 100 записей, так что в данном случае число 90 сильно завышено.

Строка 24 — CAN_SPEND = 1.45. Важный параметр – сумма денег, которую вы доверяете боту для игры. В данном случае – 1 доллар 45 центов. Это удобно в том случае, когда бот играет на одну валютную пару, а вы – на другую, ну и еще гарантирует, что бот не проиграет всё, что нажито. В общем, чем больше эта сумма, тем больше денег он может заработать.

Строка 25  — PROFIT_MARKUP = 0.001. Это сумма наценки, которую вы хотите получить. В данном случае – это 0.1% от ставки. Чем больше это число, тем больше вы заработаете, но и курс будет раздуваться больше – т.е. вам придется дольше ждать исполнения сделки. Допускается дальнейшее дробление – например, число 0.00111 подходит. Если указать ноль, то бот будет работать вхолостую, обогащая биржу. Вы при этом, терять и зарабатывать не будете.

В строке 26 указано DEBUG = True. С этим параметром будет очень «разговорчивым», он будет комментировать каждое свое действие. Когда вам это надоест, советую вместо True написать False – тогда бот будет писать только по делу.

Так же не помешало бы в код добавить обработку некоторых исключительных ситуаций, перевести на ООП и так далее – но я не вижу смысла усложнять учебный код. Тот, кто заинтересуется, сможет сделать всё это и сам. Ну, или не делать, а просто пользоваться ботом как он есть :)


Реклама



Заключение

Надеюсь, этот бот будет для вас полезен – и буду признателен обратной связи. Расскажите, каких результатов вы добились при использовании, с какими трудностями столкнулись и какие моменты показались вам непонятными.

Желаю вам стабильных, хороших заработков!

Понравилась статья? Поделить с друзьями:
  • Как написать бот кил
  • Как написать бот для торговли на бирже
  • Как написать бот для регистрации
  • Как написать боссу что заболел
  • Как написать босс на английском