T16 Finance: market charts with kinds, volume, profile, studies, drawings, compare, alerts and sync (T16a–b); quotes, book, tape and DOM (T16c); order entry, blotter, risk, options and payoff (T16d); markets, calendars, portfolio and wallet (T16e); typography::Ellipsis ends lines that gpui's truncate clipped; chart notes stack and ticks label round values
This commit is contained in:
76 files changed
+10311
-173
No files matched your search
@@ -0,0 +1,147 @@
|
||||
use gpui::{App, IntoElement, ParentElement, RenderOnce, Styled, Window, div, relative};
|
||||
|
||||
use super::quotes::{moves, price};
|
||||
use crate::{
|
||||
theme::{ActiveTheme, Radius, TextSize},
|
||||
typography::{format, tabular},
|
||||
};
|
||||
|
||||
/// The best bid and ask, and the spread between them in price and in basis points.
|
||||
#[derive(IntoElement)]
|
||||
pub struct SpreadIndicator {
|
||||
bid: f64,
|
||||
ask: f64,
|
||||
places: usize,
|
||||
red_up: bool,
|
||||
}
|
||||
|
||||
impl SpreadIndicator {
|
||||
pub fn new(bid: f64, ask: f64) -> Self {
|
||||
assert!(
|
||||
bid.is_finite() && ask.is_finite() && bid < ask,
|
||||
"a spread needs a bid below its ask"
|
||||
);
|
||||
Self {
|
||||
bid,
|
||||
ask,
|
||||
places: 2,
|
||||
red_up: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn places(mut self, places: usize) -> Self {
|
||||
self.places = places;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn red_up(mut self) -> Self {
|
||||
self.red_up = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for SpreadIndicator {
|
||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let (rise, fall) = moves(self.red_up, cx);
|
||||
let theme = cx.theme();
|
||||
let colors = &theme.colors;
|
||||
let side = |name: &'static str, value: f64, ink| {
|
||||
div()
|
||||
.flex()
|
||||
.items_baseline()
|
||||
.gap_1p5()
|
||||
.child(div().text_color(colors.fg_subtle).child(name))
|
||||
.child(
|
||||
tabular(div())
|
||||
.text_color(ink)
|
||||
.child(price(value, self.places)),
|
||||
)
|
||||
};
|
||||
let spread = self.ask - self.bid;
|
||||
let points = spread / ((self.ask + self.bid) / 2.0) * 10_000.0;
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_4()
|
||||
.text_size(theme.text_size(TextSize::Sm))
|
||||
.child(side("Bid", self.bid, rise))
|
||||
.child(
|
||||
tabular(div())
|
||||
.px_2()
|
||||
.py_0p5()
|
||||
.rounded(theme.radius(Radius::Sm))
|
||||
.bg(colors.hover)
|
||||
.text_color(colors.fg_muted)
|
||||
.child(format!("{} · {points:.1} bps", price(spread, self.places))),
|
||||
)
|
||||
.child(side("Ask", self.ask, fall))
|
||||
}
|
||||
}
|
||||
|
||||
/// The weight of waiting orders on each side as one bar split where they balance.
|
||||
#[derive(IntoElement)]
|
||||
pub struct BidAskBar {
|
||||
bids: f64,
|
||||
asks: f64,
|
||||
red_up: bool,
|
||||
}
|
||||
|
||||
impl BidAskBar {
|
||||
/// The size waiting on each side.
|
||||
pub fn new(bids: f64, asks: f64) -> Self {
|
||||
assert!(
|
||||
bids >= 0.0 && asks >= 0.0 && bids + asks > 0.0,
|
||||
"a balance needs some size"
|
||||
);
|
||||
Self {
|
||||
bids,
|
||||
asks,
|
||||
red_up: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn red_up(mut self) -> Self {
|
||||
self.red_up = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for BidAskBar {
|
||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let (rise, fall) = moves(self.red_up, cx);
|
||||
let theme = cx.theme();
|
||||
let share = self.bids / (self.bids + self.asks);
|
||||
let words = |name: &'static str, value: f64| {
|
||||
tabular(div())
|
||||
.text_color(theme.colors.fg_muted)
|
||||
.child(format!("{name} {}", format::percent(value, 0, false)))
|
||||
};
|
||||
let part = |grow: f64, ink| {
|
||||
let mut part = div().h_full().flex_basis(relative(0.0)).bg(ink);
|
||||
part.style().flex_grow = Some(grow as f32);
|
||||
part
|
||||
};
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_1()
|
||||
.text_size(theme.text_size(TextSize::Xs))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.justify_between()
|
||||
.child(words("Bids", share))
|
||||
.child(words("Asks", 1.0 - share)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.gap_0p5()
|
||||
.h(theme.meter_track())
|
||||
.rounded_full()
|
||||
.overflow_hidden()
|
||||
.child(part(share, rise).rounded_l_full())
|
||||
.child(part(1.0 - share, fall).rounded_r_full()),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user