You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

442 lines
13KB

  1. use std::thread::{self, JoinHandle};
  2. use std::sync::{Arc, Mutex, RwLock};
  3. use std::sync::mpsc::{self, Sender, Receiver, channel};
  4. use std::collections::VecDeque;
  5. use std::fmt::{self, Display, Error as FmtError, Formatter, Write};
  6. use std::time::{Instant, Duration};
  7. use chrono::{self, DateTime, Utc, TimeZone};
  8. use pub_sub::PubSub;
  9. use zmq;
  10. use influent::measurement::{Measurement, Value};
  11. use windows::{DurationWindow, Incremental};
  12. use money::{Ticker, Side};
  13. use super::file_logger;
  14. use influx;
  15. pub type Nanos = u64;
  16. pub const SECOND: u64 = 1e9 as u64;
  17. pub const MINUTE: u64 = SECOND * 60;
  18. pub const HOUR: u64 = MINUTE * 60;
  19. pub const MILLISECOND: u64 = SECOND / 1000;
  20. pub const MICROSECOND: u64 = MILLISECOND / 1000;
  21. pub fn nanos(d: Duration) -> Nanos {
  22. d.as_secs() * 1_000_000_000 + (d.subsec_nanos() as u64)
  23. }
  24. pub fn dt_nanos(t: DateTime<Utc>) -> i64 {
  25. (t.timestamp() as i64) * 1_000_000_000_i64 + (t.timestamp_subsec_nanos() as i64)
  26. }
  27. pub fn now() -> i64 { dt_nanos(Utc::now()) }
  28. pub fn tfmt(ns: Nanos) -> String {
  29. let mut f = String::new();
  30. match ns {
  31. t if t <= MICROSECOND => {
  32. write!(f, "{}ns", t);
  33. }
  34. t if t > MICROSECOND && t < MILLISECOND => {
  35. write!(f, "{}u", t / MICROSECOND);
  36. }
  37. t if t > MILLISECOND && t < SECOND => {
  38. write!(f, "{}ms", t / MILLISECOND);
  39. }
  40. t => {
  41. write!(f, "{}.{}sec", t / SECOND, t / MILLISECOND);
  42. }
  43. }
  44. f
  45. }
  46. pub fn tfmt_dur(d: Duration) -> String {
  47. tfmt(nanos(d))
  48. }
  49. pub fn tfmt_dt(dt: DateTime<Utc>) -> String {
  50. Utc::now().signed_duration_since(dt)
  51. .to_std()
  52. .map(|dur| {
  53. tfmt_dur(dur)
  54. }).unwrap_or("?".into())
  55. }
  56. pub fn tfmt_write(ns: Nanos, f: &mut Formatter) {
  57. match ns {
  58. t if t <= MICROSECOND => {
  59. write!(f, "{}ns", t);
  60. }
  61. t if t > MICROSECOND && t < MILLISECOND => {
  62. write!(f, "{}u", t / MICROSECOND);
  63. }
  64. t if t > MILLISECOND && t < SECOND => {
  65. write!(f, "{}ms", t / MILLISECOND);
  66. }
  67. t => {
  68. write!(f, "{}.{}sec", t / SECOND, t / MILLISECOND);
  69. }
  70. }
  71. }
  72. #[derive(Debug)]
  73. pub enum ExperiencedLatency {
  74. GdaxWebsocket(Duration),
  75. //GdaxWebsocketNoLock(Duration),
  76. GdaxHttpPublic(Duration),
  77. GdaxHttpPrivate(Duration),
  78. PlnxHttpPublic(Duration),
  79. PlnxHttpPrivate(Duration),
  80. PlnxOrderBook(Duration),
  81. ExmoHttpPublic(Duration),
  82. KrknHttpPublic(Duration),
  83. KrknHttpPrivate(Duration),
  84. KrknTrade(Duration, &'static str, Option<Ticker>, Option<Side>),
  85. EventLoop(Duration),
  86. Terminate
  87. }
  88. // impl Message for ExperiencedLatency {
  89. // fn kill_switch() -> Self {
  90. // ExperiencedLatency::Terminate
  91. // }
  92. // }
  93. /// represents over what period of time
  94. /// the latency measurements were taken
  95. pub trait MeasurementWindow {
  96. fn duration(&self) -> Duration;
  97. }
  98. #[derive(Debug, Clone, Copy)]
  99. pub struct WThirty;
  100. impl Default for WThirty {
  101. fn default() -> Self { WThirty {} }
  102. }
  103. impl MeasurementWindow for WThirty {
  104. fn duration(&self) -> Duration { Duration::from_secs(30) }
  105. }
  106. #[derive(Debug, Clone, Copy)]
  107. pub struct WTen;
  108. impl Default for WTen {
  109. fn default() -> Self { WTen {} }
  110. }
  111. impl MeasurementWindow for WTen {
  112. fn duration(&self) -> Duration { Duration::from_secs(10) }
  113. }
  114. #[derive(Debug, Clone)]
  115. pub struct LatencyUpdate<W>
  116. where W: MeasurementWindow
  117. {
  118. pub gdax_ws: Nanos,
  119. pub krkn_pub: Nanos,
  120. pub krkn_priv: Nanos,
  121. pub plnx_pub: Nanos,
  122. pub plnx_priv: Nanos,
  123. pub plnx_order: Nanos,
  124. pub krkn_trade_30_mean: Nanos,
  125. pub krkn_trade_30_max: Nanos,
  126. pub krkn_trade_300_mean: Nanos,
  127. pub krkn_trade_300_max: Nanos,
  128. pub plnx_last: DateTime<Utc>,
  129. pub krkn_last: DateTime<Utc>,
  130. //pub event_loop: Nanos,
  131. pub size: W,
  132. }
  133. impl<W> Default for LatencyUpdate<W>
  134. where W: MeasurementWindow + Default
  135. {
  136. fn default() -> Self {
  137. LatencyUpdate {
  138. gdax_ws: Nanos::default(),
  139. krkn_pub: Nanos::default(),
  140. krkn_priv: Nanos::default(),
  141. plnx_pub: Nanos::default(),
  142. plnx_priv: Nanos::default(),
  143. plnx_order: Nanos::default(),
  144. krkn_trade_30_mean: Nanos::default(),
  145. krkn_trade_30_max: Nanos::default(),
  146. krkn_trade_300_mean: Nanos::default(),
  147. krkn_trade_300_max: Nanos::default(),
  148. plnx_last: Utc::now(),
  149. krkn_last: Utc::now(),
  150. size: W::default()
  151. }
  152. }
  153. }
  154. impl<W> Display for LatencyUpdate<W>
  155. where W: MeasurementWindow
  156. {
  157. fn fmt(&self, f: &mut Formatter) -> fmt::Result {
  158. write!(f, " gdax ws: ");
  159. tfmt_write(self.gdax_ws, f);
  160. write!(f, "\n krkn pub: ");
  161. tfmt_write(self.krkn_pub, f);
  162. write!(f, "\n krkn priv: ");
  163. tfmt_write(self.krkn_priv, f);
  164. write!(f, "\n krkn trade 30 mean: ");
  165. tfmt_write(self.krkn_trade_30_mean, f);
  166. write!(f, "\n krkn trade 30 max: ");
  167. tfmt_write(self.krkn_trade_30_max, f);
  168. write!(f, "\n krkn trade 300 mean: ");
  169. tfmt_write(self.krkn_trade_300_mean, f);
  170. write!(f, "\n krkn trade 300 max: ");
  171. tfmt_write(self.krkn_trade_300_max, f);
  172. write!(f, "\n plnx pub: ");
  173. tfmt_write(self.plnx_pub, f);
  174. write!(f, "\n plnx priv: ");
  175. tfmt_write(self.plnx_priv, f);
  176. write!(f, "\n plnx orderbook loop: ");
  177. tfmt_write(self.plnx_order, f);
  178. //write!(f, "\n gdax ws nolock: ");
  179. //tfmt_write(self.gdax_ws_nolock, f);
  180. //write!(f, "\n event loop: ");
  181. //tfmt(self.event_loop, f);
  182. write!(f,"")
  183. }
  184. }
  185. impl<W: MeasurementWindow> LatencyUpdate<W> {
  186. pub fn measurement_window(&self) -> Duration {
  187. self.size.duration()
  188. }
  189. }
  190. pub struct LatencyManager<W>
  191. where W: MeasurementWindow + Clone + Send + Sync
  192. {
  193. pub tx: Sender<ExperiencedLatency>,
  194. pub channel: PubSub<LatencyUpdate<W>>,
  195. thread: Option<JoinHandle<()>>,
  196. }
  197. /// returns a DateTime equal to now - `dur`
  198. ///
  199. pub fn dt_from_dur(dur: Duration) -> DateTime<Utc> {
  200. let old_dur = chrono::Duration::nanoseconds(nanos(dur) as i64);
  201. Utc::now() - old_dur
  202. }
  203. struct Last {
  204. broadcast: Instant,
  205. plnx: Instant,
  206. krkn: Instant,
  207. }
  208. impl Default for Last {
  209. fn default() -> Self {
  210. Last {
  211. broadcast: Instant::now(),
  212. plnx: Instant::now(),
  213. krkn: Instant::now(),
  214. }
  215. }
  216. }
  217. //impl<W: MeasurementWindow + Clone + Send + Sync> LatencyManager<W> {
  218. impl LatencyManager<WTen> {
  219. pub fn new(w: WTen) -> Self {
  220. let (tx, rx) = channel();
  221. let tx_copy = tx.clone();
  222. let channel = PubSub::new();
  223. let channel_copy = channel.clone();
  224. let w = w.clone();
  225. let thread = Some(thread::spawn(move || {
  226. let logger = file_logger("var/log/latency-manager.log");
  227. info!(logger, "initializing zmq");
  228. let ctx = zmq::Context::new();
  229. let socket = influx::push(&ctx).unwrap();
  230. let mut buf = String::with_capacity(4096);
  231. info!(logger, "initializing DurationWindows");
  232. let mut gdax_ws = DurationWindow::new(w.duration());
  233. let mut gdax_priv = DurationWindow::new(w.duration());
  234. let mut krkn_pub = DurationWindow::new(w.duration());
  235. let mut krkn_priv = DurationWindow::new(w.duration());
  236. let mut plnx_pub = DurationWindow::new(w.duration());
  237. let mut plnx_priv = DurationWindow::new(w.duration());
  238. let mut plnx_order = DurationWindow::new(w.duration());
  239. // yes I am intentionally breaking from the hard-typed duration
  240. // window ... that was a stupid idea
  241. //
  242. let mut krkn_trade_30 = DurationWindow::new(Duration::from_secs(30));
  243. let mut krkn_trade_300 = DurationWindow::new(Duration::from_secs(300));
  244. //let mut gdax_ws_nolock = DurationWindow::new(w.duration());
  245. //let mut event_loop = DurationWindow::new(w.duration());
  246. let mut last = Last::default();
  247. thread::sleep_ms(1);
  248. info!(logger, "entering loop");
  249. loop {
  250. let loop_time = Instant::now();
  251. if let Ok(msg) = rx.recv() {
  252. debug!(logger, "new msg: {:?}", msg);
  253. match msg {
  254. ExperiencedLatency::Terminate => {
  255. crit!(logger, "terminating");
  256. break;
  257. }
  258. ExperiencedLatency::GdaxWebsocket(d) => gdax_ws.update(loop_time, d),
  259. //ExperiencedLatency::GdaxWebsocketNoLock(d) => gdax_ws_nolock.update(loop_time, d),
  260. ExperiencedLatency::GdaxHttpPrivate(d) => gdax_priv.update(loop_time, d),
  261. ExperiencedLatency::KrknHttpPublic(d) => {
  262. last.krkn = loop_time;
  263. krkn_pub.update(loop_time, d)
  264. }
  265. ExperiencedLatency::KrknHttpPrivate(d) => {
  266. last.krkn = loop_time;
  267. krkn_priv.update(loop_time, d)
  268. }
  269. ExperiencedLatency::PlnxHttpPublic(d) => {
  270. last.plnx = loop_time;
  271. plnx_pub.update(loop_time, d)
  272. }
  273. ExperiencedLatency::PlnxHttpPrivate(d) => {
  274. last.plnx = loop_time;
  275. plnx_priv.update(loop_time, d)
  276. }
  277. ExperiencedLatency::PlnxOrderBook(d) => {
  278. last.plnx = loop_time;
  279. plnx_order.update(loop_time, d)
  280. }
  281. ExperiencedLatency::KrknTrade(d, cmd, ticker, side) => {
  282. debug!(logger, "new KrknTrade";
  283. "cmd" => cmd);
  284. last.krkn = loop_time;
  285. let n = DurationWindow::nanos(d);
  286. krkn_trade_30.update(loop_time, d);
  287. krkn_trade_300.update(loop_time, d);
  288. let ticker_s = ticker.map(|t| t.to_string()).unwrap_or("".into());
  289. let side_s = side.map(|s| s.to_string()).unwrap_or("".into());
  290. let mut m = Measurement::new("krkn_trade_api");
  291. m.add_field("nanos", Value::Integer(n as i64));
  292. m.add_tag("cmd", cmd);
  293. if ticker.is_some() {
  294. m.add_tag("ticker", &ticker_s);
  295. }
  296. if side.is_some() {
  297. m.add_tag("side", &side_s);
  298. }
  299. m.set_timestamp(now());
  300. influx::serialize(&m, &mut buf);
  301. socket.send_str(&buf, 0);
  302. buf.clear();
  303. }
  304. //ExperiencedLatency::EventLoop(d) => event_loop.update(Instant::now(), d),
  305. other => {
  306. warn!(logger, "unexpected msg: {:?}", other);
  307. }
  308. }
  309. }
  310. if loop_time - last.broadcast > Duration::from_millis(100) {
  311. debug!(logger, "initalizing broadcast");
  312. // note - because we mutated the Window instances
  313. // above, we need a fresh Instant to avoid less than other
  314. // panic
  315. //
  316. krkn_trade_30.refresh(&loop_time);
  317. krkn_trade_300.refresh(&loop_time);
  318. let update = LatencyUpdate {
  319. gdax_ws: gdax_ws.refresh(&loop_time).mean_nanos(),
  320. //gdax_ws_nolock: gdax_ws_nolock.refresh(&loop_time).mean_nanos(),
  321. krkn_pub: krkn_pub.refresh(&loop_time).mean_nanos(),
  322. krkn_priv: krkn_priv.refresh(&loop_time).mean_nanos(),
  323. plnx_pub: plnx_pub.refresh(&loop_time).mean_nanos(),
  324. plnx_priv: plnx_priv.refresh(&loop_time).mean_nanos(),
  325. plnx_order: plnx_order.refresh(&loop_time).mean_nanos(),
  326. krkn_trade_30_mean: krkn_trade_30.mean_nanos(),
  327. krkn_trade_30_max: krkn_trade_30.max_nanos().unwrap_or(0),
  328. krkn_trade_300_mean: krkn_trade_300.mean_nanos(),
  329. krkn_trade_300_max: krkn_trade_300.max_nanos().unwrap_or(0),
  330. plnx_last: dt_from_dur(loop_time - last.plnx),
  331. krkn_last: dt_from_dur(loop_time - last.krkn),
  332. //event_loop: event_loop.refresh(&now).mean_nanos(),
  333. size: w.clone(),
  334. };
  335. channel.send(update);
  336. last.broadcast = loop_time;
  337. debug!(logger, "sent broadcast");
  338. }
  339. }
  340. crit!(logger, "goodbye");
  341. }));
  342. LatencyManager {
  343. tx: tx_copy,
  344. channel: channel_copy,
  345. thread
  346. }
  347. }
  348. }