Добрый день, дорогой %username%!
Совсем недавно я узнал про такую замечательную вещь, как биткоин. Не секрет, что последние 2-3 месяца наблюдался бурный рост этой криптовалюты. Казалось бы, ну есть у нас криптовалюта, а сбывать ее где? После моего предыдущего поста у меня появилось несколько лайткоинов. Естественно, я начал думать о способе сбыта легкой криптовалюты. Немного погуглив, я набрел на биржу BTC-E и, о великий котэ, увидел заветную кнопочку «Trade API».
С этого момента судьба следующих пары-тройки дней для меня была предопределена — я загорелся идеей воспользоваться этим самым API и сделать миллионы грязных долларов написать бота, который автоматически бы сбывал и покупал ресурсы. А так как я fully proficient (взято с моего профиля на elance.com) в Objective C, на нем я писать и буду.
Три дня прошло, и я все-таки осилил API. Зачем я выкладываю все это в открытый доступ? Что же, на это есть ряд причин:
- Пора уже начинать делать что-то open source
- Нужно популяризировать криптовалюту
- Логики в моем «наброске» очень мало, так что алгоритмы купли\продажи заинтересованному придется писать самостоятельно
- Мне банально нужен человек, финансист, который наглядно объяснит какими путями нужно идти. Возможно, даже согласится работать вместе
Внимание! Под катом разбор основных моментов работы с API; подводные камни, о которые мне пришлось споткнуться; исходники.
1. Разбор API
Заходим на сайт биржы в раздел FAQ, открываем вкладку «API». Можно покликать по Public Api, ответы будут приходить в JSON формате. Нравится мне этот формат. Уже хорошо, идем дальше.
Переходим по ссылке «Trade Api». Что мы видим? Нужно просто отправлять POST запросы и будет нам счастье! Отлично, а как это на Objective C-то реализовать? Вот незадача! До этого момента я ведь никогда и не думал о подобном на моем родном языке. Ничего страшного, разберемся.
Что у нас тут? Посылаем ключ API из профиля в заголовок «api»; POST запрос добавляем как тело запроса; а в «sign» передаем хеш нашего тела запроса, подписанный секретным ключом «secret». Круто. Где их взять? Заходим в профиль.
Ничего себе! И то, и то в одном месте! Вот это да, пока что я иду на правильном пути. Главное не забыть установить нужные права для наших ключей.
Давайте взглянем на тело стандартного ответа с публичного запроса из API. Попробуем узнать курс BTC/USD. Шлепнем по запросу. Получаем примерно следующее:
{"ticker":{"high":139,"low":126.6,"avg":132.8,"vol":971784.85609,"vol_cur":7345.76864,"last":136.396,"buy":137,"sell":136.396,"server_time":1365246479}}
Про JSON рассказывать не буду, в интернете по нему полно туториалов. Нас интересуют покупка и продажа. Напишем небольшой код для реализации запроса и его обработки! Вперед к коду!
- (void)updateLtcToUsdRate { dispatch_async(kBgQueue, ^{ NSData *data = [apiHandler getResponseFromPublicServerUrl:@"https://btc-e.com/api/2/ltc_usd/ticker"]; NSError* error; NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; NSDictionary* ticker = [json objectForKey:@"ticker"]; NSString *sell = [ticker objectForKey:@"sell"]; NSString *buy = [ticker objectForKey:@"buy"]; ltcToUsdSellRateLabel.stringValue = addDollarSign(sell); ltcToUsdBuyRateLabel.stringValue = addDollarSign(buy); }); } - (NSData *)getResponseFromPublicServerUrl:(NSString *)urlString { NSURL *url = [NSURL URLWithString:urlString]; NSData *data = [NSData dataWithContentsOfURL:url]; return data; }
Пройдемся по коду. В проекте у нас пара классов, и BtceApiHandler работает с запросами на сервер. getResponseFromPublicServerUrl — это метод BtceApiHandler класса. Здесь никаких POST запросов отправлять не нужно, просто забираем данные с сервера. Дальше слегка обрабатываем JSON и получаем значения sell и buy. Покажем их на экран нашему пользователю (пока что только нам).
А что за addDollarSign? А вот тут я постиг приятные плюшки функций в Objective C. До сегодняшнего момента я их редко использовал, старался их избегать, но теперь легким движением руки появляются вот такие крендельки. Мелочь, а приятно.
NSString *addDollarSign(NSString *string) { NSString *newString = [NSString stringWithFormat:@"$%@",string]; return newString; }
Ну, с публичным API вроде как разобрались, если нет — Вам дорога к мануалу.
Что же происходит с личным API? Пока я разобрался с POST запросами в Objective C, я потерял приличное количество нервных клеток. Да и в самом API есть примеры алгоритмов и ввода, а что должно быть на выходе между Вами и сервером — не понятно. Пришлось спрашивать в чате самой биржи. Благо, приятные люди там есть, и мне помогли.
В чем проблема? Наверное, в том, что я никогда и не работал с POST запросами на своем родном языке. Только Java, только хардкор. Прыгнем в код класса BtceApiHandler.
- (void)setupInitialValues { api_key = @"P55XJOOF-207D9CCC-A7NDKIYK-KIMFCOXC-WJPJ21XY"; secret_key = @"5bb4f0c55d6100d583505dc98eaff1df7d1ba281b5f8365686090d5cbbdb9846"; }
Нужно инициализировать две важные переменные. Позже можно будет сделать специальное окошко и так далее, но я просто захордкодил ключи. Не обольщайтесь, их я уже отключил.
- (NSData *)getResponseFromServerForPost:(NSDictionary *)postDictionary { NSString *post; int i = 0; for (NSString *key in [postDictionary allKeys]) { NSString *value = [postDictionary objectForKey:key]; if (i==0) post = [NSString stringWithFormat:@"%@=%@", key, value]; else post = [NSString stringWithFormat:@"%@&%@=%@", post, key, value]; i++; } post = [NSString stringWithFormat:@"%@&nonce=%@", post, getNonce()]; NSString *signedPost = hmacForKeyAndData(secret_key, post); NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:@"https://btc-e.com/tapi"]]; [request setHTTPMethod:@"POST"]; [request setValue:api_key forHTTPHeaderField:@"key"]; [request setValue:signedPost forHTTPHeaderField:@"sign"]; [request setHTTPBody:[post dataUsingEncoding: NSUTF8StringEncoding]]; NSURLResponse *theResponse = NULL; NSError *theError = NULL; NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&theError]; return responseData; }
А вот и монструозный метод отправки и обработки POST запроса! Мы передаем в него аргументом NSDictionary, в котором храним связки параметр-значение. Первая часть преобразует наш словарь в POST запрос, вторая часть забивает наш запрос стандартными данными (тип данных, url, key, sign), третья часть посылает запрос и возвращает NSData c ответом.
NSString *hmacForKeyAndData(NSString *key, NSString *data) { const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA512, cKey, strlen(cKey), cData, strlen(cData), cHMAC); NSMutableString *hashString = [NSMutableString stringWithCapacity:sizeof(cHMAC) * 2]; for (int i = 0; i < sizeof(cHMAC); i++) { [hashString appendFormat:@"%02x", cHMAC[i]]; } return hashString; }
Особое внимание стоит уделить коду подписи данных в «sign». Почему? Да я на него убил больше суток! Больше суток хождения по интернетам и стаковерфловам. Происходит все просто: используя встроенные возможности языка, мы подписываем ключом данные и вытягиваем SHA512 хеш. Цикл, думаю, объяснять не стоит — там и так все очевидно. Раньше пытался получить значение через description наших данных — не получалось. Пришлось спросить на stackoverflow про этот небольшой циклик.
NSString *getNonce() { NSTimeInterval timeStamp = [[NSDate date] timeIntervalSinceDate:[NSDate dateWithString:@"2012-04-18 00:00:01 +0600"]]; int currentNonce = [NSNumber numberWithDouble: timeStamp].intValue; NSString *nonceString = [NSString stringWithFormat:@"%i",currentNonce]; return nonceString; }
А еще есть функция getNonce(). Параметр nonce передавать в POST запросе обязательно. Это инкремент, так что каждое последующее число должно быть больше предыдущего. Вот такие пироги. Ах да, эта функция считает время, прошедшее с моего совершеннолетия.
2. Что умеет делать наш бот?
Пока мы можем мониторить интересную информацию, смотреть за ростом и падением криптовалют. Ничего особенного, можно сказать, я просто обернул API в Objective C. Небольшой скриншот програмки-на-коленке:
3. Что делать дальше?
API побеждено, дело техники закончено. Впереди автоматизация процесса — а это уйма работы над алгоритмами. Сам я далеко не финансист, да что уж, даже не начинающий трейдер на рынке. Если вдруг кто из желающих здесь захочет со мной поработать, и возможно даже поднять немного денег — милости прошу ко мне в различные IM, контакты есть в моем хабрацентре.
А вдруг кто из Objective C программистов захочет позаниматься в свободное время этими механизмами и созданием со мной юзер-френдли UI? Опять же, милости прошу в IM.
Где код?
Исходники тут. Приятного просмотра. Все под лицензией GPL (первая попавшаяся мне open source лицензия). Качайте, компилируйте, пользуйтесь. Не продавайте.
Если Вы нашли какую-то опечатку и\или неточность — напишите, пожалуйста, мне в личку или в комментарии. Всем спасибо, а я пойду спать. Это API заставляло меня спать по 4-6 часов в сутки. Наконец-то высплюсь. Всем спасибо.
ссылка на оригинал статьи http://habrahabr.ru/post/175703/
Добавить комментарий