Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions crates/pine-builtins/src/box/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,74 @@ impl BoxCopy {
}
}

/// box.set_top_left_point(id, point) - Set the top-left corner from a `chart.point`.
#[derive(BuiltinFunction)]
#[builtin(name = "box.set_top_left_point")]
struct BoxSetTopLeftPoint<O: PineOutput + BoxOutput> {
id: f64,
point: Value<O>,
}

impl<O: PineOutput + BoxOutput> BoxSetTopLeftPoint<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let (left, top) = crate::chart::point_coords(&self.point)?;
let id = self.id as usize;
let box_obj = ctx
.output
.get_box_mut(id)
.ok_or_else(|| RuntimeError::TypeError(format!("Box with id {} not found", id)))?;
box_obj.left = left;
box_obj.top = top;
Ok(Value::Na)
}
}

/// box.set_bottom_right_point(id, point) - Set the bottom-right corner from a
/// `chart.point`.
#[derive(BuiltinFunction)]
#[builtin(name = "box.set_bottom_right_point")]
struct BoxSetBottomRightPoint<O: PineOutput + BoxOutput> {
id: f64,
point: Value<O>,
}

impl<O: PineOutput + BoxOutput> BoxSetBottomRightPoint<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let (right, bottom) = crate::chart::point_coords(&self.point)?;
let id = self.id as usize;
let box_obj = ctx
.output
.get_box_mut(id)
.ok_or_else(|| RuntimeError::TypeError(format!("Box with id {} not found", id)))?;
box_obj.right = right;
box_obj.bottom = bottom;
Ok(Value::Na)
}
}

/// box.set_text_formatting(id, text_formatting) - A rendering hint the output
/// model does not store; validates the box exists and is otherwise a no-op.
#[derive(BuiltinFunction)]
#[builtin(name = "box.set_text_formatting", output = BoxOutput)]
struct BoxSetTextFormatting {
id: f64,
text_formatting: String,
}

impl BoxSetTextFormatting {
fn execute<O: PineOutput + BoxOutput>(
&self,
ctx: &mut Interpreter<O>,
) -> Result<Value<O>, RuntimeError> {
let _ = &self.text_formatting;
let id = self.id as usize;
ctx.output
.get_box_mut(id)
.ok_or_else(|| RuntimeError::TypeError(format!("Box with id {} not found", id)))?;
Ok(Value::Na)
}
}

/// Register the box namespace with all functions
pub fn register<O: PineOutput + BoxOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();
Expand Down Expand Up @@ -687,6 +755,22 @@ pub fn register<O: PineOutput + BoxOutput>() -> Value<O> {
members.insert("get_bottom".to_string(), BoxGetBottom::builtin_value::<O>());
members.insert("delete".to_string(), BoxDelete::builtin_value::<O>());
members.insert("copy".to_string(), BoxCopy::builtin_value::<O>());
members.insert(
"set_top_left_point".to_string(),
BoxSetTopLeftPoint::<O>::builtin_value(),
);
members.insert(
"set_bottom_right_point".to_string(),
BoxSetBottomRightPoint::<O>::builtin_value(),
);
members.insert(
"set_text_formatting".to_string(),
BoxSetTextFormatting::builtin_value::<O>(),
);
members.insert(
"all".to_string(),
Value::Array(Rc::new(RefCell::new(Vec::new()))),
);

Value::Object {
type_name: "box".to_string(),
Expand Down
19 changes: 19 additions & 0 deletions crates/pine-builtins/src/chart/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ impl<O: PineOutput> ChartPointCopy<O> {
}
}

/// The `(x, y)` a `chart.point` denotes for a drawing: `x` is the bar index (or
/// the time when the index is `na`), `y` is the price. Used by the
/// `line`/`box`/`label` point setters.
pub fn point_coords<O: PineOutput>(point: &Value<O>) -> Result<(f64, f64), RuntimeError> {
let Value::Object { fields, .. } = point else {
return Err(RuntimeError::TypeError("expected a chart.point".into()));
};
let fields = fields.borrow();
let read = |name: &str| {
fields
.get(name)
.and_then(|v| v.as_number().ok())
.unwrap_or(f64::NAN)
};
let index = read("index");
let x = if index.is_nan() { read("time") } else { index };
Ok((x, read("price")))
}

/// Register the `chart.*` namespace object.
pub fn register<O: PineOutput>() -> Value<O> {
let mut point_ns: HashMap<String, Value<O>> = HashMap::new();
Expand Down
26 changes: 26 additions & 0 deletions crates/pine-builtins/src/constants/adjustment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `adjustment.*` constants (price-adjustment mode for `request.security`).
const ADJUSTMENTS: &[&str] = &["none", "splits", "dividends"];

/// Register the adjustment namespace with all its constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for adjustment in ADJUSTMENTS {
members.insert(
adjustment.to_string(),
Value::String(adjustment.to_string()),
);
}

Value::Object {
type_name: "adjustment".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
27 changes: 27 additions & 0 deletions crates/pine-builtins/src/constants/backadjustment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `backadjustment.*` constants (continuous-futures back-adjustment mode for
/// `request.security`).
const BACKADJUSTMENTS: &[&str] = &["inherit", "off", "on"];

/// Register the backadjustment namespace with all its constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for backadjustment in BACKADJUSTMENTS {
members.insert(
backadjustment.to_string(),
Value::String(backadjustment.to_string()),
);
}

Value::Object {
type_name: "backadjustment".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
23 changes: 23 additions & 0 deletions crates/pine-builtins/src/constants/font.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `font.*` constants (font families for label/table/box text).
const FONTS: &[&str] = &["family_default", "family_monospace"];

/// Register the font namespace with all font constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for font in FONTS {
members.insert(font.to_string(), Value::String(font.to_string()));
}

Value::Object {
type_name: "font".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
7 changes: 7 additions & 0 deletions crates/pine-builtins/src/constants/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
//! constants. Only `size`, `shape`, and `location` live here for now; the other
//! constant families remain in their own modules.

pub mod adjustment;
pub mod backadjustment;
pub mod barmerge;
pub mod display;
pub mod extend;
pub mod font;
pub mod format;
pub mod location;
pub mod order;
pub mod position;
pub mod scale;
pub mod settlement_as_close;
pub mod shape;
pub mod size;
pub mod splits;
pub mod text;
pub mod xloc;
pub mod yloc;
23 changes: 23 additions & 0 deletions crates/pine-builtins/src/constants/scale.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `scale.*` constants (which price scale an indicator is attached to).
const SCALES: &[&str] = &["left", "right", "none"];

/// Register the scale namespace with all scale constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for scale in SCALES {
members.insert(scale.to_string(), Value::String(scale.to_string()));
}

Value::Object {
type_name: "scale".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
27 changes: 27 additions & 0 deletions crates/pine-builtins/src/constants/settlement_as_close.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `settlement_as_close.*` constants (whether futures use the settlement
/// price as the close, for `request.security`).
const SETTLEMENTS: &[&str] = &["inherit", "off", "on"];

/// Register the settlement_as_close namespace with all its constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for settlement in SETTLEMENTS {
members.insert(
settlement.to_string(),
Value::String(settlement.to_string()),
);
}

Value::Object {
type_name: "settlement_as_close".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
23 changes: 23 additions & 0 deletions crates/pine-builtins/src/constants/splits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `splits.*` constants (which field of a `request.splits` call to read).
const SPLITS: &[&str] = &["denominator", "numerator"];

/// Register the splits namespace with all splits constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for split in SPLITS {
members.insert(split.to_string(), Value::String(split.to_string()));
}

Value::Object {
type_name: "splits".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
3 changes: 3 additions & 0 deletions crates/pine-builtins/src/constants/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const TEXTS: &[&str] = &[
"align_bottom",
"wrap_none",
"wrap_auto",
"format_none",
"format_bold",
"format_italic",
];

/// Register the text namespace with all text constants.
Expand Down
23 changes: 23 additions & 0 deletions crates/pine-builtins/src/constants/yloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// The `yloc.*` constants (vertical placement for labels/lines relative to a bar).
const YLOCS: &[&str] = &["abovebar", "belowbar", "price"];

/// Register the yloc namespace with all yloc constants.
pub fn register<O: PineOutput>() -> Value<O> {
let mut members: HashMap<String, Value<O>> = HashMap::new();

for yloc in YLOCS {
members.insert(yloc.to_string(), Value::String(yloc.to_string()));
}

Value::Object {
type_name: "yloc".to_string(),
fields: Rc::new(RefCell::new(members)),
call: None,
}
}
29 changes: 29 additions & 0 deletions crates/pine-builtins/src/dividends/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//! The `dividends.*` namespace: dividend-field constants and upcoming-dividend
//! variables. The forward-looking values are `na` without a fundamentals feed.

use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// Register the `dividends.*` namespace object.
pub fn register<O: PineOutput>() -> Value<O> {
let mut fields: HashMap<String, Value<O>> = HashMap::new();

// Which dividend figure `request.dividends` returns.
for constant in ["gross", "net"] {
fields.insert(constant.to_string(), Value::String(constant.to_string()));
}

// Upcoming dividends, `na` without a fundamentals feed.
for var in ["future_amount", "future_ex_date", "future_pay_date"] {
fields.insert(var.to_string(), Value::Na);
}

Value::Object {
type_name: "dividends".to_string(),
fields: Rc::new(RefCell::new(fields)),
call: None,
}
}
34 changes: 34 additions & 0 deletions crates/pine-builtins/src/earnings/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! The `earnings.*` namespace: earnings-field constants and upcoming-earnings
//! variables. The forward-looking values are `na` without a fundamentals feed.

use pine_core::PineOutput;
use pine_interpreter::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/// Register the `earnings.*` namespace object.
pub fn register<O: PineOutput>() -> Value<O> {
let mut fields: HashMap<String, Value<O>> = HashMap::new();

// Which earnings figure `request.earnings` returns.
for constant in ["actual", "estimate", "standardized"] {
fields.insert(constant.to_string(), Value::String(constant.to_string()));
}

// Upcoming earnings, `na` without a fundamentals feed.
for var in [
"future_eps",
"future_revenue",
"future_time",
"future_period_end_time",
] {
fields.insert(var.to_string(), Value::Na);
}

Value::Object {
type_name: "earnings".to_string(),
fields: Rc::new(RefCell::new(fields)),
call: None,
}
}
Loading
Loading