tradingbot/src/coin_health_check_team/request_candles.rs
2024-04-21 01:36:34 +09:00

784 lines
29 KiB
Rust

use crate::database_control::*;
use futures::future::try_join_all;
use futures::{stream, StreamExt};
use reqwest::{Client, ClientBuilder, Response};
use serde::Deserialize;
use serde_json::Value;
use sqlx::{Error, FromRow};
use std::borrow::{Borrow, BorrowMut};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::{join, sync::Mutex, time::*};
#[derive(Debug, Clone)]
pub struct CandleData {
pub open_time: i64,
pub open_price: f64,
pub high_price: f64,
pub low_price: f64,
pub close_price: f64,
pub volume: f64,
pub close_time: i64,
pub quote_asset_volume: f64,
pub number_of_trades: i64,
pub taker_buy_base_asset_volume: f64,
pub taker_buy_quote_asset_volume: f64,
pub ignore_this: f64,
}
impl CandleData {
fn new() -> CandleData {
let candle_data = CandleData {
open_time: 0,
open_price: 0.0,
high_price: 0.0,
low_price: 0.0,
close_price: 0.0,
volume: 0.0,
close_time: 0,
quote_asset_volume: 0.0,
number_of_trades: 0,
taker_buy_base_asset_volume: 0.0,
taker_buy_quote_asset_volume: 0.0,
ignore_this: 0.0,
};
candle_data
}
}
// fetch the list of valid usdt trades
#[derive(Debug, FromRow, Clone)]
struct Symbols {
symbol: String,
}
// request candlestick data from endpoint for each symbol (Weight(IP) 1)
// use the following intervals: 1m, 30m, 1d, 1w, 1mon (1M)
async fn request_candlestick_data(
symbol: String,
interval: &String,
client: &Client,
candle_set: &mut HashMap<String, Vec<CandleData>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut query = String::from("https://api.binance.com/api/v3/klines?");
query.push_str("&symbol=");
query.push_str(symbol.as_str());
query.push_str("&limit=");
query.push_str("1000");
query.push_str("&interval=");
if interval == "1mon" {
query.push_str("1M");
} else {
query.push_str(interval.as_str());
}
let response = client.get(query).send().await?;
let mut body = String::new();
body = response.text_with_charset("utf-8").await?;
if interval == "1m" || interval == "30m" {
de_candle_json(symbol, &interval, &body, candle_set).await?;
} else if interval == "1d" || interval == "1w" || interval == "1mon" {
de_candle_json2(symbol, &interval, &body, candle_set).await?;
}
Ok(())
}
async fn de_candle_json(
symbol: String,
interval: &String,
body: &String,
candle_map: &mut HashMap<String, Vec<CandleData>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let v: Value = serde_json::from_str(body.as_str())?;
let mut into_vec = v.as_array();
if into_vec == None {
return Err("Err")?;
}
let mut candle_vec: Vec<CandleData> = Vec::new();
let mut candle_data = CandleData::new();
for element in into_vec.unwrap() {
let inner_into_vec = element.as_array().unwrap();
candle_data.open_time = element[0].as_i64().unwrap();
candle_data.open_price = element[1].as_str().unwrap().parse::<f64>().unwrap();
candle_data.high_price = element[2].as_str().unwrap().parse::<f64>().unwrap();
candle_data.low_price = element[3].as_str().unwrap().parse::<f64>().unwrap();
candle_data.close_price = element[4].as_str().unwrap().parse::<f64>().unwrap();
candle_data.volume = element[5].as_str().unwrap().parse::<f64>().unwrap();
candle_data.close_time = element[6].as_i64().unwrap();
candle_data.quote_asset_volume = element[7].as_str().unwrap().parse::<f64>().unwrap();
candle_data.number_of_trades = element[8].as_i64().unwrap();
candle_data.taker_buy_base_asset_volume =
element[9].as_str().unwrap().parse::<f64>().unwrap();
candle_data.taker_buy_quote_asset_volume =
element[10].as_str().unwrap().parse::<f64>().unwrap();
candle_data.ignore_this = element[11].as_str().unwrap().parse::<f64>().unwrap();
candle_vec.push(candle_data.clone());
}
candle_map.insert(symbol, candle_vec);
// let search_result = candle_set.iter().position(|x| x.0 == symbol);
// match search_result {
// Some(T) => {
// candle_set[T].1 = candle_vec;
// },
// None => {
// candle_set.push((symbol, candle_vec));
// }
// }
Ok(())
}
async fn de_candle_json2(
symbol: String,
interval: &String,
body: &String,
candle_map: &mut HashMap<String, Vec<CandleData>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let v: Value = serde_json::from_str(body.as_str())?;
let mut into_vec = v.as_array();
if into_vec == None {
return Err("Err")?;
}
let mut candle_vec: Vec<CandleData> = Vec::new();
let mut candle_data = CandleData::new();
for element in into_vec.unwrap() {
let inner_into_vec = element.as_array().unwrap();
candle_data.open_time = element[0].as_i64().unwrap();
candle_data.open_price = element[1].as_str().unwrap().parse::<f64>().unwrap();
candle_data.high_price = element[2].as_str().unwrap().parse::<f64>().unwrap();
candle_data.low_price = element[3].as_str().unwrap().parse::<f64>().unwrap();
candle_data.close_price = element[4].as_str().unwrap().parse::<f64>().unwrap();
candle_data.volume = element[5].as_str().unwrap().parse::<f64>().unwrap();
candle_data.close_time = element[6].as_i64().unwrap();
candle_data.quote_asset_volume = element[7].as_str().unwrap().parse::<f64>().unwrap();
candle_data.number_of_trades = element[8].as_i64().unwrap();
candle_data.taker_buy_base_asset_volume =
element[9].as_str().unwrap().parse::<f64>().unwrap();
candle_data.taker_buy_quote_asset_volume =
element[10].as_str().unwrap().parse::<f64>().unwrap();
candle_data.ignore_this = element[11].as_str().unwrap().parse::<f64>().unwrap();
candle_vec.push(candle_data.clone());
}
if let Some(value) = candle_map.get_mut(&symbol) {
*value = candle_vec;
} else {
candle_map.insert(symbol, candle_vec);
}
Ok(())
}
// // request candlestick data from endpoint for each symbol (Weight(IP) 1)
// // use the following intervals: 1m, 30m, 1d, 1w, 1mon(1M)
// async fn request_candlestick_data(symbol: &String, interval: &String, client: &Client) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// let mut query = String::from("https://api.binance.com/api/v3/klines?");
// query.push_str("&symbol=");
// query.push_str(symbol.as_str());
// query.push_str("&interval=");
// if interval == "1mon" {
// query.push_str("1M");
// } else {
// query.push_str(interval.as_str());
// }
// let response = client.get(query).send().await?;
// let mut body = String::new();
// body = response.text_with_charset("utf-8").await?;
// de_candle_json(&symbol, &interval, &body).await?;
// // println!(" candle {} {} 완료", symbol, interval);
// Ok(())
// }
// // for initialization
// pub async fn request_candlestick_initial (symbol_vec: &Vec<String>, interval: &String) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// const CONCURRENT_REQUESTS: usize = 50;
// #[derive(Clone, Debug)]
// struct QuerySet {
// symbol: String,
// query_url: String,
// interval: String,
// body: String,
// }
// let client = ClientBuilder::new().connect_timeout(tokio::time::Duration::from_millis(10000)).build().unwrap();
// let mut query_set = QuerySet{ symbol: String::new(), query_url: String::new(), interval: String::new(), body: String::new() };
// let mut query_set_vec: Vec<QuerySet> = Vec::new();
// for symbol in symbol_vec {
// let mut query_url = String::from("https://api.binance.com/api/v3/klines?");
// query_url.push_str("&interval=");
// if interval == "1mon" {
// query_url.push_str("1M");
// } else {
// query_url.push_str(interval.as_str());
// }
// query_url.push_str("&symbol=");
// query_url.push_str(symbol.as_str());
// query_set.query_url = query_url;
// query_set.symbol = symbol.clone();
// query_set.interval = interval.clone();
// query_set_vec.push(query_set.clone());
// }
// let bodies = stream::iter(query_set_vec)
// .map(|mut query_set| {
// let client = &client;
// async move {
// let mut response = client.get(query_set.query_url.clone()).send().await.unwrap();
// let mut body = response.text_with_charset("utf-8").await;
// while let Err(e) = body {
// response = client.get(query_set.query_url.clone()).send().await.unwrap();
// body = response.text_with_charset("utf-8").await;
// sleep(Duration::from_secs(1)).await;
// }
// query_set.body = body.unwrap();
// query_set
// }
// })
// .buffer_unordered(CONCURRENT_REQUESTS);
// bodies.for_each(|query_set| async move {de_candle_json(&query_set.symbol.to_string(), &query_set.interval.to_string(), &query_set.body.to_string()).await;}).await;
// Ok(())
// }
// for initialization
pub async fn request_candlestick_initial(
symbol: String,
interval: &String,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut candle_set: HashMap<String, Vec<CandleData>> = HashMap::new();
let client = ClientBuilder::new()
.timeout(tokio::time::Duration::from_millis(20000))
.build()
.unwrap();
let mut query = String::from("https://api.binance.com/api/v3/klines?");
// query.push_str("&limit=");
// query.push_str("200");
query.push_str("&symbol=");
query.push_str(symbol.as_str());
query.push_str("&interval=");
if interval == "1mon" {
query.push_str("1M");
} else {
query.push_str(interval.as_str());
}
let mut response = client.get(&query).send().await;
while let Err(e) = response {
response = client.get(&query).send().await;
sleep(Duration::from_secs(1)).await;
}
let mut body = response.unwrap().text_with_charset("utf-8").await;
while let Err(e) = body {
response = client.get(&query).send().await;
while let Err(e) = response {
response = client.get(&query).send().await;
sleep(Duration::from_secs(1)).await;
}
body = response.unwrap().text_with_charset("utf-8").await;
}
de_candle_json(symbol, &interval, &body.unwrap(), &mut candle_set).await?;
Ok(())
}
// pub async fn request_candlestick_initial (symbol: &String, interval: &String) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// let client = ClientBuilder::new().timeout(tokio::time::Duration::from_millis(10000)).build().unwrap();
// let mut query = String::from("https://api.binance.com/api/v3/klines?");
// query.push_str("&symbol=");
// query.push_str(symbol.as_str());
// query.push_str("&interval=");
// if interval == "1mon" {
// query.push_str("1M");
// } else {
// query.push_str(interval.as_str());
// }
//
// let mut response = client.get(&query).send().await;
// let temp = reqwest::get("http://site.with.redirect.loop").await;
// if let Err(e) = temp{
// e.
// }
// if let Err(e) = response {
// if e.is_timeout() {
// loop{
// println!(">>> [timeout] retry fetching candle data: {} {}", symbol, interval);
// tokio::time::sleep(Duration::from_secs(1)).await;
// response = client.get(&query).send().await?;
// if response.is_ok() { break; }
// }
// }
// } else {
// let mut body = String::new();
// body = response.unwrap().text_with_charset("utf-8").await.unwrap();
// de_candle_json(&symbol, &interval, &body).await.unwrap();
// }
//
// Ok(())
// }
// async fn de_candle_json(symbol: &String, interval: &String, body: &String) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// let v: Value = serde_json::from_str(body.as_str())?;
// let mut into_vec = v.as_array();
// if into_vec == None {
// return Err("Err")?
// }
// // let mut one_candle_data: &Vec<Value> = Vec::new();
// let columns = vec!["openTime", "openPrice", "highPrice","lowPrice", "closePrice",
// "volume", "closeTime", "quoteAssetVolume", "numberOfTrades", "takerBuyBaseAssetVolume",
// "takerBuyQuoteAssetVolume", "ignoreThis"];
// let mut value_wrapper: Vec<Vec<String>> = Vec::new();
// for element in into_vec.unwrap() {
// let inner_into_vec = element.as_array().unwrap();
// let mut value_vec = Vec::new();
// for element in inner_into_vec {
// if element.is_number() {
// value_vec.push(element.as_i64().unwrap().to_string());
// } else if element.is_string() {
// value_vec.push(element.as_str().unwrap().to_string());
// } else {
// println!("Elements in body msg are changed. Please update parsing in de_candle_json.");
// }
// }
// value_wrapper.push(value_vec);
// }
// store_candle_db(&symbol, &interval, &columns, value_wrapper).await;
// Ok(())
// }
async fn store_candle_db(
symbol: &String,
interval: &String,
columns: &Vec<&str>,
value_wrapper: Vec<Vec<String>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut table_name = String::from("candle_");
table_name.push_str(symbol.as_str());
table_name.push('_');
table_name.push_str(interval.as_str());
delete_all_rows(&table_name).await.unwrap();
insert_records(&table_name, columns, &value_wrapper)
.await
.unwrap();
Ok(())
}
pub async fn create_candle_table(
symbol: &String,
interval: &String,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut table_name = String::from("candle_");
table_name.push_str(symbol.as_str());
table_name.push('_');
table_name.push_str(interval.as_str());
let initial_table = vec![
("id", "integer", Some("PK, AI")),
("openTime", "bigint", None),
("openPrice", "double", None),
("highPrice", "double", None),
("lowPrice", "double", None),
("closePrice", "double", None),
("volume", "double", None),
("closeTime", "bigint", None),
("quoteAssetVolume", "double", None),
("numberOfTrades", "int", None),
("takerBuyBaseAssetVolume", "double", None),
("takerBuyQuoteAssetVolume", "double", None),
("ignoreThis", "double", None),
];
let initial_columns = vec![
"openTime",
"openPrice",
"highPrice",
"lowPrice",
"closePrice",
"volume",
"closeTime",
"quoteAssetVolume",
"numberOfTrades",
"takerBuyBaseAssetVolume",
"takerBuyQuoteAssetVolume",
"ignoreThis",
];
let initial_values = vec![
String::from("0"),
String::from("0.0"),
String::from("0.0"),
String::from("0.0"),
String::from("0.0"),
String::from("0.0"),
String::from("0"),
String::from("0.0"),
String::from("0"),
String::from("0.0"),
String::from("0.0"),
String::from("0.0"),
];
let table_condition = Some("ENGINE = MEMORY");
new_table(&table_name, &initial_table, &table_condition)
.await
.unwrap();
insert_one_record(&table_name, &initial_columns, &initial_values)
.await
.unwrap();
Ok(())
}
// for fetching 1m and 30m candle
pub async fn fetch_candle_parallel(
interval: &String,
candle_map: &mut HashMap<String, Vec<CandleData>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let instant = Instant::now();
let fetch_table_name = String::from("valid_usdt_trades");
let column_name = String::from("symbol");
let condition = None;
let mut symbols = Symbols {
symbol: String::new(),
};
let mut select_result = select_record(&fetch_table_name, &column_name, &condition, &symbols)
.await
.unwrap();
// 심볼들을 20개씩 청스로 나누어 테스크를 생성하고 각 태스크 별로 병렬로 처리한다.
let chunks = select_result.chunks(20);
let nbr_chunks = chunks.len();
let mut candle_vec_arc_wrapper: Vec<Arc<Mutex<HashMap<String, Vec<CandleData>>>>> = Vec::new();
for _ in 0..nbr_chunks {
let mut candle_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
let mut candle_vec_arc = Arc::new(Mutex::new(candle_map_temp));
candle_vec_arc_wrapper.push(candle_vec_arc);
}
let mut task_vec = Vec::new();
let mut index = 0;
for chunk in chunks {
let candle_arc = Arc::clone(&candle_vec_arc_wrapper[index]);
let chunk_vec = chunk.to_vec();
let interval_clone = interval.clone();
task_vec.push(tokio::spawn(async move {
repeat_task(interval_clone, chunk_vec, candle_arc).await;
}));
index += 1;
}
let result = try_join_all(task_vec).await;
match result {
Ok(T) => {
let mut candle_buffer: HashMap<String, Vec<CandleData>> = HashMap::new();
for element in candle_vec_arc_wrapper {
let a = element.lock().await.clone();
for (symbol, candle_data) in a {
candle_buffer.insert(symbol, candle_data);
}
}
*candle_map = candle_buffer;
// println!(" candle {} 완료 elapsed:{:.2}s", interval.as_str(), instant.elapsed().as_secs_f32());
}
Err(E) => {
panic!("Failed to fetch candle data!")
}
}
Ok(())
}
async fn repeat_task(
interval: String,
symbol_vec: Vec<Symbols>,
my_count: Arc<Mutex<HashMap<String, Vec<CandleData>>>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let client = ClientBuilder::new()
.timeout(tokio::time::Duration::from_millis(5000))
.build()
.unwrap();
for element in symbol_vec {
let mut candle_set_lock = my_count.lock().await;
request_candlestick_data(element.symbol, &interval, &client, &mut candle_set_lock).await;
sleep(Duration::from_millis(200)).await;
}
Ok(())
}
// for fetching 1d, 1w, and 1mon candle
pub async fn fetch_candle_delay(
interval: &String,
candle_vec: &mut HashMap<String, Vec<CandleData>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let instant_func = Instant::now();
let server_epoch = server_epoch().await;
let client = ClientBuilder::new()
.timeout(tokio::time::Duration::from_millis(5000))
.build()
.unwrap();
// to decide keeping retry or not as the current server status from database
#[derive(Debug, FromRow, Clone)]
struct ServerStatus {
server_on: bool,
}
let serverhealth_table_name = String::from("serverhealth");
let serverhealth_column_name = String::from("server_on");
let serverhealth_condition = None;
let mut serverhealth = ServerStatus { server_on: true };
// fetch the list of valid usdt trades
#[derive(Debug, FromRow)]
struct Symbols {
symbol: String,
}
let fetch_table_name = String::from("valid_usdt_trades");
let column_name = String::from("symbol");
let condition = None;
let mut symbols = Symbols {
symbol: String::new(),
};
let mut select_result = select_record(&fetch_table_name, &column_name, &condition, &symbols)
.await
.unwrap();
let mut time_wait = 0;
if interval == "30m" {
time_wait = 1_000;
} else if interval == "1d" {
time_wait = 5_000;
} else if interval == "1w" {
time_wait = 10_000;
} else {
time_wait = 15_000;
}
let mut server_on_result = select_record(
&serverhealth_table_name,
&serverhealth_column_name,
&serverhealth_condition,
&serverhealth,
)
.await
.unwrap();
serverhealth.server_on = server_on_result[0].server_on;
for element in select_result {
let instant = Instant::now();
server_on_result = select_record(
&serverhealth_table_name,
&serverhealth_column_name,
&serverhealth_condition,
&serverhealth,
)
.await
.unwrap();
serverhealth.server_on = server_on_result[0].server_on;
{
request_candlestick_data(element.symbol, &interval, &client, candle_vec).await;
}
// sleep for 10secs for 1d, 20secs for 1w, 30secs for 1mon
if time_wait > instant.elapsed().as_millis() {
sleep(Duration::from_millis(
(time_wait - instant.elapsed().as_millis()) as u64,
))
.await;
}
}
// println!(" candle {} 완료 elapsed:{:.2}s", interval, instant_func.elapsed().as_secs());
Ok(())
}
// pub async fn fetch_candle_1w() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// let server_epoch = server_epoch().await;
// let client = ClientBuilder::new().timeout(tokio::time::Duration::from_millis(1200)).build().unwrap();
// // to decide keeping retry or not as the current server status from database
// #[derive(Debug, FromRow, Clone)]
// struct ServerStatus {
// server_on: bool,
// }
// let serverhealth_table_name = String::from("serverhealth");
// let serverhealth_column_name = String::from("server_on");
// let serverhealth_condition = None;
// let mut serverhealth = ServerStatus { server_on: true };
// // fetch the list of valid usdt trades
// #[derive(Debug, FromRow)]
// struct Symbols {
// symbol: String,
// }
// let fetch_table_name = String::from("valid_usdt_trades");
// let column_name = String::from("symbol");
// let condition = None;
// let mut symbols = Symbols { symbol: String::new() };
// let mut select_result = select_record(&fetch_table_name, &column_name, &condition, &symbols).await.unwrap();
// let interval = String::from("1w");
// let column_name = String::from("closeTime");
// let condition = Some(String::from("ORDER BY id DESC LIMIT 1"));
// #[derive(Debug, FromRow)]
// struct CloseTime {
// closetime: i64,
// }
// let mut server_on_result = select_record(&serverhealth_table_name, &serverhealth_column_name, &serverhealth_condition, &serverhealth).await.unwrap();
// serverhealth.server_on = server_on_result[0].server_on;
// let instant_1w = Instant::now();
// for element in select_result {
// let instant = Instant::now();
// server_on_result = select_record(&serverhealth_table_name, &serverhealth_column_name, &serverhealth_condition, &serverhealth).await.unwrap();
// serverhealth.server_on = server_on_result[0].server_on;
// if serverhealth.server_on == true {
// let mut closetime = CloseTime { closetime: 0 };
// let mut table_name = String::from("candle_");
// table_name.push_str(element.symbol.as_str());
// table_name.push_str("_1w");
// let mut exists_result = exists_table(&table_name).await;
// if exists_result == false { create_candle_table(&element.symbol, &interval).await.unwrap(); }
// let mut select_result = select_record(&table_name, &column_name, &condition, &closetime).await.unwrap();
// if (select_result[0].closetime as u64) < server_epoch {
// while let Err(e) = request_candlestick_data(&element.symbol, &interval, &client).await
// {
// server_on_result = select_record(&serverhealth_table_name, &serverhealth_column_name, &serverhealth_condition, &serverhealth).await.unwrap();
// serverhealth.server_on = server_on_result[0].server_on;
// if serverhealth.server_on == false { break; }
// println!(">>> retry to fetch candlestick {} {} data from endpoint.", &element.symbol, &interval);
// sleep(Duration::from_millis(500)).await;
// }
// }
// }
// // sleep as much as the loop recurs per 20 seconds if all operation finished within 20 seconds.
// if 20_000_000_000 > instant.elapsed().as_nanos() {
// sleep(Duration::from_nanos((20_000_000_000 - instant.elapsed().as_nanos()) as u64)).await;
// }
// }
// println!(" candle 1w 완료 elapsed:{:.2}s", instant_1w.elapsed().as_secs());
// Ok(())
// }
// pub async fn fetch_candle_1mon() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// let server_epoch = server_epoch().await;
// let client = ClientBuilder::new().timeout(tokio::time::Duration::from_millis(1200)).build().unwrap();
// // to decide keeping retry or not as the current server status from database
// #[derive(Debug, FromRow, Clone)]
// struct ServerStatus {
// server_on: bool,
// }
// let serverhealth_table_name = String::from("serverhealth");
// let serverhealth_column_name = String::from("server_on");
// let serverhealth_condition = None;
// let mut serverhealth = ServerStatus { server_on: true };
// // fetch the list of valid usdt trades
// #[derive(Debug, FromRow)]
// struct Symbols {
// symbol: String,
// }
// let fetch_table_name = String::from("valid_usdt_trades");
// let column_name = String::from("symbol");
// let condition = None;
// let mut symbols = Symbols { symbol: String::new() };
// let mut select_result = select_record(&fetch_table_name, &column_name, &condition, &symbols).await.unwrap();
// let interval = String::from("1mon");
// let column_name = String::from("closeTime");
// let condition = Some(String::from("ORDER BY id DESC LIMIT 1"));
// #[derive(Debug, FromRow)]
// struct CloseTime {
// closetime: i64,
// }
// let mut server_on_result = select_record(&serverhealth_table_name, &serverhealth_column_name, &serverhealth_condition, &serverhealth).await.unwrap();
// serverhealth.server_on = server_on_result[0].server_on;
// let instant_1mon = Instant::now();
// for element in select_result {
// let instant = Instant::now();
// server_on_result = select_record(&serverhealth_table_name, &serverhealth_column_name, &serverhealth_condition, &serverhealth).await.unwrap();
// serverhealth.server_on = server_on_result[0].server_on;
// if serverhealth.server_on == true {
// let mut closetime = CloseTime { closetime: 0 };
// let mut table_name = String::from("candle_");
// table_name.push_str(element.symbol.as_str());
// table_name.push_str("_1mon");
// let mut exists_result = exists_table(&table_name).await;
// if exists_result == false { create_candle_table(&element.symbol, &interval).await.unwrap(); }
// let mut select_result = select_record(&table_name, &column_name, &condition, &closetime).await.unwrap();
// if (select_result[0].closetime as u64) < server_epoch {
// while let Err(e) = request_candlestick_data(&element.symbol, &interval, &client).await
// {
// server_on_result = select_record(&serverhealth_table_name, &serverhealth_column_name, &serverhealth_condition, &serverhealth).await.unwrap();
// serverhealth.server_on = server_on_result[0].server_on;
// if serverhealth.server_on == false { break; }
// println!(">>> retry to fetch candlestick {} {} data from endpoint.", &element.symbol, &interval);
// sleep(Duration::from_millis(500)).await;
// }
// }
// }
// // sleep as much as the loop recurs per 30 seconds if all operation finished within 30 seconds.
// if 30_000_000_000 > instant.elapsed().as_nanos() {
// sleep(Duration::from_nanos((30_000_000_000 - instant.elapsed().as_nanos()) as u64)).await;
// }
// }
// println!(" candle 1mon 완료 elapsed:{:.2}s", instant_1mon.elapsed().as_secs());
// Ok(())
// }
async fn server_epoch() -> u64 {
#[derive(Debug, FromRow)]
struct ServerEpoch {
server_epoch: u64,
}
let table_name = String::from("time");
let columns = String::from("*");
let condition = None;
let mut time_info = ServerEpoch { server_epoch: 0 };
let select_result = select_record(&table_name, &columns, &condition, &time_info)
.await
.unwrap();
select_result.first().unwrap().server_epoch
}