Добрый день, дорогой %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 часов в сутки. Наконец-то высплюсь. Всем спасибо.
Автор: backmeupplz
Лалка:D зечем замазывать API ключи на первом фото, если ты их потом в коде показываешь:D api_key = @”P55XJOOF-207D9CCC-A7NDKIYK-KIMFCOXC-WJPJ21XY”;
secret_key = @”5bb4f0c55d6100d583505dc98eaff1df7d1ba281b5f8365686090d5cbbdb9846″;