Продолжаем создавать бот для автоматического доступа к бирже Betfair. В конце концов, в последней части, у нас получится полностью законченный бот. Что же он будет делать? Ну, допустим, пусть он будет расставлять минимальную ставку LAY с коэффициентом 1.01 на все вновь появившиеся теннисные рынки.
Итак, в это части добавим в бот, который уже умеет логиниться к бирже, способность получать новые рынки. Внизу измененный код, из предыдущего примера, который умеет это делать. Изменить следует основной фал исходного кода программы JavaApplication1.java (не забудьте подставить свой логин и пароль к бирже в строках 27 и 28)
package javaapplication1; import com.betfair.publicapi.types.exchange.v5.ArrayOfInt; import com.betfair.publicapi.types.exchange.v5.GetAllMarketsReq; import com.betfair.publicapi.types.exchange.v5.GetAllMarketsResp; import com.betfair.publicapi.types.global.v3.LoginReq; import com.betfair.publicapi.types.global.v3.LoginResp; import com.betfair.publicapi.v3.bfglobalservice.BFGlobalService; import com.betfair.publicapi.v3.bfglobalservice.BFGlobalService_Service; import com.betfair.publicapi.v5.bfexchangeservice.BFExchangeService; import com.betfair.publicapi.v5.bfexchangeservice.BFExchangeService_Service; import java.util.ArrayList; public class JavaApplication1 { public static void main(String[] args) { String sessionToken = ""; com.betfair.publicapi.types.exchange.v5.APIRequestHeader exchangeHeader = new com.betfair.publicapi.types.exchange.v5.APIRequestHeader(); BFGlobalService_Service WSDLService_Global = new BFGlobalService_Service(); BFGlobalService WSDLPort_Global = WSDLService_Global.getBFGlobalService(); BFExchangeService_Service WSDLService_Exchange = new BFExchangeService_Service(); BFExchangeService WSDLPort_Exchange = WSDLService_Exchange.getBFExchangeService(); LoginReq loginRequest = new LoginReq(); loginRequest.setUsername("mylogToBetfair"); loginRequest.setPassword("mypassword"); loginRequest.setProductId(82); loginRequest.setVendorSoftwareId(0); loginRequest.setIpAddress("0"); loginRequest.setLocationId(0); LoginResp result = WSDLPort_Global.login(loginRequest); System.out.println("Логин на Betfair - " + result.getErrorCode().toString()); if (result.getErrorCode().toString().equals("OK")) { sessionToken = result.getHeader().getSessionToken(); System.out.println("Текущий session Token - " + result.getHeader().getSessionToken()); } else { // По какой-то причине логин не получился. Выход из программы System.exit(0); } /*********** Готовим запрос и запрашиваем все теннисные рынки **************/ // Готовим заголовок для запроса exchangeHeader.setSessionToken(sessionToken); exchangeHeader.setClientStamp(0); // Готовим запрос всех теннисных рынков GetAllMarketsReq allMarketsRequest = new GetAllMarketsReq(); // Добавляем в запрос заголовок запроса allMarketsRequest.setHeader(exchangeHeader); allMarketsRequest.setLocale("en"); // Создаем массив интересущих нас видов спорта ArrayOfInt array = new ArrayOfInt(); // Добавляем в этот массив число 2 соответствующее теннису // Например, для футбола это 1. // Соответствие чисел видам спорта смотрим здесь http://data.betfair.com/sportids.htm?rfr=15929 array.getInt().add(2); // Подставляем в массив видов спорта в запрос allMarketsRequest.setEventTypeIds(array); // Запрос готов! Отправляем его на сайт Betfair GetAllMarketsResp resp = WSDLPort_Exchange.getAllMarkets(allMarketsRequest); System.out.println("Ответ на запрос рынков - " + resp.getErrorCode().toString()); // Проверяем ответ. Сравниваем его со строкой ОК if (!resp.getErrorCode().toString().equals("OK")) { // Запрос завершился неудачно. Выходим из программы System.out.println("Ответ на запрос рынков - " + resp.getErrorCode().toString()); System.exit(0); } // Разбираем весь запрос. ArrayList<MyMarketInfo>> markets = MarketsParser.parseMarkets(resp.getMarketData()); if (markets.isEmpty()) { System.out.println("Не получено ни одного рынка в ответе на запрос рынков"); System.exit(0); } else { System.out.println("Получено всего " + markets.size() + " рынков в ответе на запрос рынков"); } // Из всего множества теннисных рынков формируем массив // который будет содержать только рынки Match Odds (ставки на победителя в матче) ArrayLis<MyMarketInfo> matchOddsMarkets = new ArrayList<MyMarketInfo>(); for (int i = 0; i < markets.size(); i++) { if (markets.get(i).getMarketName().equals("Match Odds")) { matchOddsMarkets.add(markets.get(i)); } } // Печатаем количество Match Odds рынков или выходим из программы если таких рынков не обнаружено if (matchOddsMarkets.isEmpty()) { System.out.println("Не найдено ни одного Match Odds рынка"); System.exit(0); } else { System.out.println("Получено всего " + matchOddsMarkets.size() + " Macth Odds рынков в ответе на запрос теннисных рынков"); } // Печатаем все полученные рынки на экран for (int i = 0; i < matchOddsMarkets.size(); i++) { System.out.println((i+1) + ". " + matchOddsMarkets.get(i).getEventName() + ", " + matchOddsMarkets.get(i).getMarketMenuPath()); } } } class MarketsParser { } class MyMarketInfo { }
Пробежимся по коду.
Строки 48, 49. Готовим заголовок для запроса рынков. Подставляем в заголовок сессионный ключ полученный в ответе на логин. Это делается для того что бы не надо было в каждом запросе вставлять свой логин и пароль.
Строки 52-63. Готовим запрос к бирже для получения всех возможных теннисных рынков. То, что нас интересуют только теннисные рынки указано в строке 61. Об этом говорит число 2. Если б нас интересовал еще и футбол, то надо было бы написать в следующей строке
Строка 66. Отправляем, только что сформированный запрос на биржу.
Строки 68-74. Проверяем код ошибки и завершаем программу если код ошибки отличается от строки "ОК".
Строки 76-82. Разбираем ответ биржи. Внимание! Ответ от биржи будет получен в виде одной строки следующего уродливого вида -
Строки 86-91. Фильтруем все найденные рынки и отбираем рынки которые называются Match Odds. Что соответствует обычным ставкам на победителя в теннисном матче. Собираем отфильтрованные рынки в переменной массиве matchOddsMarkets.
Строки 92-103. Распечатываем количество полученных теннисных рынков, а также все Match Odds рынки с названиями рынков.
Весь исходный текст программы в одном файле JavaApplication1.java
Строки 48, 49. Готовим заголовок для запроса рынков. Подставляем в заголовок сессионный ключ полученный в ответе на логин. Это делается для того что бы не надо было в каждом запросе вставлять свой логин и пароль.
Строки 52-63. Готовим запрос к бирже для получения всех возможных теннисных рынков. То, что нас интересуют только теннисные рынки указано в строке 61. Об этом говорит число 2. Если б нас интересовал еще и футбол, то надо было бы написать в следующей строке
array.getInt().add(
2
)
. У каждого вида спорта есть свое число которое надо подставлять в запрос. Список всех возможных чисел смотрим здесь.Строка 66. Отправляем, только что сформированный запрос на биржу.
Строки 68-74. Проверяем код ошибки и завершаем программу если код ошибки отличается от строки "ОК".
Строки 76-82. Разбираем ответ биржи. Внимание! Ответ от биржи будет получен в виде одной строки следующего уродливого вида -
106955486~Match Odds~O~ACTIVE~1349238600000~\Tennis\Group A\China Open 2012\Womens Tournament\Second Round Matches\Bartoli v Morita~/2/26900942/26901463/26901449/26901677/106955486~0~1~CHN~1349038369954~2~1~0.0~N~Y:106955487~Set Betting~O~ACTIVE~1349238600000~\Tennis\Group A\China Open 2012\Womens Tournament\Second Round Matches\Bartoli v Morita~/2/26900942/26901463/26901449/26901677/106955487~0~1~CHN~1349038369954~4~1~0.0~N~YНовичку в программировании поначалу сложно будет извлечь полезную информацию из этой информационной свалки. Поэтому я облегчу ваши страдания. Я написал специальный класс который будет за мгновение ока разбирать эту строку и создавать отдельный объект типа MyMarketInfo для каждого найденного рынка. Что бы не загромождать страницу я не привел описания этих классов здесь. Однако, я приложу весь исходный текст программы целиком в конце этой заметки. Вам надо будет только скопипасить его на место кода написанного в предыдущем посте.
Строки 86-91. Фильтруем все найденные рынки и отбираем рынки которые называются Match Odds. Что соответствует обычным ставкам на победителя в теннисном матче. Собираем отфильтрованные рынки в переменной массиве matchOddsMarkets.
Строки 92-103. Распечатываем количество полученных теннисных рынков, а также все Match Odds рынки с названиями рынков.
Весь исходный текст программы в одном файле JavaApplication1.java
Спасибо за пост. Ты монстр!!! А почему именно выбрал Java?
ОтветитьУдалитьТема многим интересна. У некоторых даже руки дойдут до реализации. Надеюсь и у меня тоже, когда будет больше времени )
ОтветитьУдалитьСпасибо за посты!
Спасибо за тему, автор!
ОтветитьУдалитьЯ вот из-за желания написать бота взялся с нуля учить сишарп. А тут такой доступный материал на Яве...Просьба поделиться соображениями с точки зрения выбора языка.
Яву я выбрал в качестве языка по причине того, что язык этот намного проще чем С#/C++ и непрограммисту освоить его намного легче.
ОтветитьУдалитьСпасибо!
ОтветитьУдалитьПривет! Как то читал в твоем блоге, что ты хочешь перебраться на Гоа, у меня тоже есть такая задумка, только на зиму,летом там дожди и говорят делать там нечего. Хотел бы узнать там можно найти недорогое жилье с инетом, и вообще может интересна любая инфа ,может и ты захочешь вдвоем все же дешевле и легче.Заранее благодарен.Константин.
ОтветитьУдалитьНа Гоа?... Я такую глупость написать не мог. Что там делать всю зиму? Сидеть на пляже и медитировать с такими же бомжеватыми идиотами у которых нет денег чтобы поехать в нормальное место?
ОтветитьУдалитьНе. Я стараюсь избегать мест скопления большого количества дураков. Уж куда-куда, а на Гоа я точно никогда не поеду :-)
Извини, значит ошибся, я давно читал,значит не про гоа ты писал. Сорри)))
ОтветитьУдалитьАвтору преогромная благодарность! Разобрался, поменял рынки на футбольные, как мне надо. Все ок. Только хочется решить еще пару задач:
ОтветитьУдалить1. Как можно узнать, регулируемый рынок или нет?
2. Для фишинга нерыночных кэфов хочу, чтобы бот мониторил появление новых рынков и сигналил об этом, скажем на почту. Думаю, что здесь не обойтись без использования БД. Что порекомендуешь, MySQL или что-то еще? Подозреваю, что ява умеет работать со многими СУБД, но еще не гуглил :)
1. Слово "регулируемый" не совсем понимаю. Если ты имеешь в виду "Managed", то узнать это из API можно только одним способом. Рынок ставок на победителя будет называться не "Match Odds", а "Match Odds Unmanaged"
ОтветитьУдалить2. Java, действительно, умеет работать с любой базой данных. Однако, для такого пустяка создавать базу данных я бы не стал.
1. Спасибо, все просто оказывается. :)
Удалить2. Я планировал такой алгоритм. Бот в цикле, скажем каждые пять минут, проверяет рынки и сравнивает, есть ли они уже в базе или нет. Если нет, то сигналит об этом и пишет в базу, чтобы в следующий прогон не сигналить их. Если БД не использовать, тогда что? В текстовый файлик писать и с ним сравнивать? Или у тебя другая мысль?
Можно и базу. Но для работы с базами данных надо обладать кое-какими дополнительными знаниями. Без которых мало что у тебя получится.
УдалитьА можно так. Данные хранить в обычном массиве объектов, затем после добавления нового элемента, используя writeObject() пишешь в файл. Если программа упала и надо массив прочитать опять, используешь readObject() и получаешь свой массив как ни в чем ни бывало назад. Я думаю это проще чем работать с базами данных. Читай на тему "Сериализация в Ява" - http://habrahabr.ru/post/60317
В качестве массива, разумеется, надо юзать класс ArrayList. В нем есть все что тебе надо, а самое главное метод поиска уже существующего элемента.
УдалитьFD, подскажи как заставить бот следить за двумя рынками на одном матче на протяжении, например, часа и проставляться тогда, когда кофы будут соответствовать заданным. Спасибо.
ОтветитьУдалитьИзучай теорию многопоточных приложений. Для современного программиста реализовывать многопоточность проще простого.
ОтветитьУдалитьДобрый день! когда ожидать пятую часть повествования?
ОтветитьУдалить