Skip to content

Instantly share code, notes, and snippets.

@ggomagundan
Last active December 18, 2019 07:06
Show Gist options
  • Save ggomagundan/5134d29e7ee37cc7aa568c347ade3c88 to your computer and use it in GitHub Desktop.
Save ggomagundan/5134d29e7ee37cc7aa568c347ade3c88 to your computer and use it in GitHub Desktop.
[package]
name = "poloniex"
version = "0.1.0"
authors = ["Kai <ggogun@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = "0.10.0-alpha.2"
tokio = { version = "0.2.0-alpha.6" }
serde = {version = "1.0", features = ["derive"] }
serde_json = "1.0"
dotenv = "0.14.1"
dotenv_codegen = "0.14.1"
chrono = { version = "0.4", features = ["serde"] }
rust-crypto = "^0.2"
url = "2.1.0"
hmac = "0.6.2"
sha2 = "0.7.1"
data-encoding = "2.1.2"
cargo-geiger = "0.7.3"
#[macro_use]
extern crate dotenv_codegen;
use std::collections::HashMap;
mod poloniex_requests;
mod models;
use models::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>>{
// let ticker_response: HashMap<String, Ticker> = poloniex_requests::get_ticker().await?;
// println!("Tciker: {:?}\n", ticker_response);
// let balance_response: HashMap<String, String> = poloniex_requests::get_balances().await?;
// println!("Balance: {:?}\n", balance_response);
let btc_loan_response: LoanOrders = poloniex_requests::get_load_orders("btc".to_owned()).await?;
let mut copied_loan = btc_loan_response;
let mut offers = copied_loan.offers().clone();
offers.sort_by(|a, b| a.rate().cmp(&b.rate()));
println!("BTC Best Loand: {:?}\n", offers[0]);
println!("BTC Best Loand Rate: {:?}\n", offers[0].rate());
let eth_loan_response: LoanOrders = poloniex_requests::get_load_orders("eth".to_owned()).await?;
copied_loan = eth_loan_response;
offers = copied_loan.offers().clone();
offers.sort_by(|a, b| a.rate().cmp(&b.rate()));
println!("ETH Best Loand: {:?}\n", offers[0]);
let eth_best_rate = offers[0].rate().parse::<f32>().unwrap();
println!("ETH Best Loand Rate: {:?}\n", eth_best_rate);
let all_balance_response: HashMap<String, CompleteBalances> = poloniex_requests::get_complete_balances().await?;
// println!("All Balance: {:?}\n", all_balance_response);
println!("BTC Balance : {:?}\n", all_balance_response.get("BTC"));
println!("ETH Balance : {:?}\n", all_balance_response.get("ETH"));
let eth_balance = all_balance_response.get("ETH").unwrap().available();
let availe_eth = eth_balance.parse::<f64>().unwrap();
println!("ETH Avail Balance : {:?} => {:?}\n",eth_balance, availe_eth);
// Will be change to percent (0.001 => 0.1%)
let loan_offer: LoanOffer = poloniex_requests::make_new_load_offer("ETH".to_string(), availe_eth, 2, false, eth_best_rate).await?;
println!("Offers {:?}", loan_offer);
Ok(())
}
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug)]
pub struct Ticker {
id: u32,
last: String
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Balances {
name: String,
balance: String
}
#[derive(Deserialize, Serialize, Debug)]
#[allow(non_snake_case)]
pub struct CompleteBalances {
available: String,
onOrders: String,
btcValue: String
}
#[derive(Deserialize, Serialize, Debug)]
#[allow(non_snake_case)]
pub struct LoanOffer {
success: u32,
message: String,
orderID: u32
}
#[derive(Deserialize, Serialize, Debug )]
pub struct LoanOrders {
offers: Vec<LoanOrder>,
demands: Vec<LoanOrder>
}
#[derive(Deserialize, Serialize, Debug, Clone)]
#[allow(non_snake_case)]
pub struct LoanOrder {
rate: String,
amount: String,
rangeMin: u32,
rangeMax: u32
}
impl LoanOrders {
// Immutable access.
pub fn offers(self) -> Vec<LoanOrder> {
self.offers
}
pub fn demands(self) -> Vec<LoanOrder> {
self.demands
}
}
impl LoanOrder {
pub fn rate(&self) -> &String {
&self.rate
}
}
impl CompleteBalances {
pub fn available(&self) -> &String {
&self.available
}
pub fn onOrders(&self) -> &String {
&self.onOrders
}
}
use crate::models::LoanOffer;
use crate::models::LoanOrders;
use reqwest;
use std::collections::HashMap;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha512;
use data_encoding::HEXLOWER;
use chrono::prelude::*;
use crate::models::Ticker;
use crate::models::CompleteBalances;
static PUBLIC_API_ENDPOINT: &str = "https://poloniex.com/public";
static PRIVATE_API_ENDPOINT: &str = "https://poloniex.com/tradingApi";
static POLONIEX_KET: &str = dotenv!("POLONIEX_KEY");
use serde_json;
pub async fn get_ticker()
-> Result<HashMap<String, Ticker>, Box<dyn std::error::Error>> {
let ticker_url = get_get_path("returnTicker");
let response: HashMap<String, Ticker> = reqwest::get(&ticker_url).await?.json::<HashMap<String, Ticker>>().await?;
Ok(response)
}
pub async fn get_load_orders(currency: String)
-> Result<LoanOrders, Box<dyn std::error::Error>> {
let mut ticker_url = get_get_path("returnLoanOrders");
ticker_url = format!("{}&currency={}", ticker_url, currency.to_uppercase());
let response: LoanOrders = reqwest::get(&ticker_url).await?.json::<LoanOrders>().await?;
Ok(response)
}
pub async fn get_balances()
-> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
let post_params = get_post_data("returnBalances".to_string());
let body_data = create_body_data(post_params.clone());
let sign_data = get_sign_data(&body_data);
let post_resp = reqwest::Client::new().post(PRIVATE_API_ENDPOINT)
.header("Sign", sign_data)
.header("Key", POLONIEX_KET)
.form(&post_params)
.send()
.await?.bytes().await?;
let response: HashMap<String, String> = serde_json::from_slice(&post_resp).unwrap();
Ok(response)
}
pub async fn get_complete_balances()
-> Result<HashMap<String, CompleteBalances>, Box<dyn std::error::Error>> {
let mut post_params = get_post_data("returnCompleteBalances".to_string());
post_params.insert("account".to_owned(), "all".to_owned());
let body_data = create_body_data(post_params.clone());
let sign_data = get_sign_data(&body_data);
let post_resp = reqwest::Client::new().post(PRIVATE_API_ENDPOINT)
.header("Sign", sign_data)
.header("Key", POLONIEX_KET)
.form(&post_params)
.send()
.await?.bytes().await?;
let response: HashMap<String, CompleteBalances> = serde_json::from_slice(&post_resp).unwrap();
Ok(response)
}
pub async fn make_new_load_offer(currency: String, amount: f64, duration: u32, auto_renew: bool, rate: f32)
-> Result<LoanOffer, Box<dyn std::error::Error>> {
let mut post_params = get_post_data("createLoanOffer".to_string());
post_params.insert("currency".to_owned(), currency.to_owned());
post_params.insert("amount".to_owned(), amount.to_string().to_owned());
post_params.insert("duration".to_owned(), duration.to_string().to_owned());
post_params.insert("autoRenew".to_owned(), (auto_renew as i32).to_string().to_owned());
post_params.insert("lendingRate".to_owned(), rate.to_string().to_owned());
let body_data = create_body_data(post_params.clone());
let sign_data = get_sign_data(&body_data);
let response = reqwest::Client::new().post(PRIVATE_API_ENDPOINT)
.header("Sign", sign_data)
.header("Key", POLONIEX_KET)
.form(&post_params)
.send()
.await?.bytes().await?;
//.json::<LoanOffer>().await?;
println!("return: {:?}", response);
let response1: LoanOffer = serde_json::from_slice(&response).unwrap();
Ok(response1)
}
fn create_body_data(params_data: HashMap<String, String>) -> String {
let encoded: String = params_data.into_iter()
.map(|data| format!("{}={}",data.0,data.1) )
.collect::<Vec<String>>().join("&");
encoded
}
fn get_get_path(str: &str) -> String {
let ret = format!("{}?command={}", PUBLIC_API_ENDPOINT, str);
ret
}
fn get_post_data(command: String)
-> HashMap<String, String> {
let mut params = HashMap::new();
let current_time = get_current_time();
params.insert("command".to_owned(), command.to_owned());
params.insert("nonce".to_owned(), current_time.to_owned());
params
}
fn get_sign_data(data: &str) -> String {
let sec_key: &str = dotenv!("POLONIEX_SECRET");
let mut hmac = Hmac::new(Sha512::new(), &sec_key.as_bytes());
hmac.input(data.as_bytes());
HEXLOWER.encode(hmac.result().code())
}
fn get_current_time() -> String {
let local: DateTime<Local> = Local::now();
local.format("%s0000000").to_string()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment