use crate::catalog::{
IndicatorSignature, IndicatorCategory, ParamConstraint, IndicatorRoleKind,
};
use crate::bar_indicators::indicator_value::IndicatorValueKind;
use super::super::bar_indicator_id::BarIndicatorId;
use once_cell::sync::Lazy;
use std::collections::HashMap;
pub const CATEGORY: IndicatorCategory = IndicatorCategory::Position;
pub fn signature_avwap_distance() -> IndicatorSignature {
IndicatorSignature::builder("AVWAP_DIST", CATEGORY)
.name("Anchored VWAP Distance")
.description("Relative distance to anchored VWAP")
.metadata("type", "distance")
.machine_id(BarIndicatorId::AvwapDist)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("AvwapDist")
.alias("avwap_dist")
.alias("ANCHOREDVWAPDISTANCE")
.alias("AnchoredVWAPDistance")
.alias("anchoredvwapdistance")
.alias("anchored_vwap_distance")
.alias("ANCHORED_VWAP_DISTANCE")
.alias("Anchored_Vwap_Distance")
.build()
}
pub fn signature_vwap_distance() -> IndicatorSignature {
IndicatorSignature::builder("VWAP_DIST", CATEGORY)
.name("VWAP Distance")
.description("Relative distance to VWAP")
.metadata("type", "distance")
.machine_id(BarIndicatorId::VwapDist)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("VwapDist")
.alias("vwap_dist")
.alias("VWAPDISTANCE")
.alias("VWAPDistance")
.alias("vwapdistance")
.alias("vwap_distance")
.alias("VWAP_DISTANCE")
.alias("Vwap_Distance")
.build()
}
pub fn signature_central_pivot_range() -> IndicatorSignature {
IndicatorSignature::builder("CPR", CATEGORY)
.name("Central Pivot Range")
.description("Central pivot range for support/resistance")
.metadata("type", "pivot")
.metadata("timeframe", "daily")
.machine_id(BarIndicatorId::Cpr)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Triple)
.validated()
.alias("Cpr")
.alias("cpr")
.alias("CENTRALPIVOTRANGE")
.alias("CentralPivotRange")
.alias("centralpivotrange")
.alias("central_pivot_range")
.alias("CENTRAL_PIVOT_RANGE")
.alias("Central_Pivot_Range")
.build()
}
pub fn signature_day_of_week_in_month() -> IndicatorSignature {
IndicatorSignature::builder("DAY_WEEK_MONTH", CATEGORY)
.name("Day of Week in Month")
.description("Which week of the month (1st, 2nd, 3rd, 4th, 5th)")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::DayWeekMonth)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("DayWeekMonth")
.alias("day_week_month")
.alias("DAYOFWEEKINMONTH")
.alias("DayofWeekinMonth")
.alias("dayofweekinmonth")
.alias("day_of_week_in_month")
.alias("DAY_OF_WEEK_IN_MONTH")
.alias("Day_Of_Week_In_Month")
.build()
}
pub fn signature_dayofmonth_weekofquarter_effect() -> IndicatorSignature {
IndicatorSignature::builder("DOM_WOQ", CATEGORY)
.name("Day of Month & Week of Quarter Effect")
.description("Combined day of month and week of quarter seasonality")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::DomWoq)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("DomWoq")
.alias("dom_woq")
.alias("DAYOFMONTH&WEEKOFQUARTEREFFECT")
.alias("DayofMonth&WeekofQuarterEffect")
.alias("dayofmonth&weekofquartereffect")
.alias("day_of_month_&_week_of_quarter_effect")
.alias("DAY_OF_MONTH_&_WEEK_OF_QUARTER_EFFECT")
.alias("Day_Of_Month_&_Week_Of_Quarter_Effect")
.build()
}
pub fn signature_distance_to_levels() -> IndicatorSignature {
IndicatorSignature::builder("DIST_LEVELS", CATEGORY)
.name("Distance to Levels")
.description("Distance to support/resistance levels")
.add_constraint(ParamConstraint::period(10, 500, 50))
.metadata("type", "distance")
.machine_id(BarIndicatorId::DistLevels)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Double)
.validated()
.alias("DistLevels")
.alias("dist_levels")
.alias("DISTANCETOLEVELS")
.alias("DistancetoLevels")
.alias("distancetolevels")
.alias("distance_to_levels")
.alias("DISTANCE_TO_LEVELS")
.alias("Distance_To_Levels")
.build()
}
pub fn signature_holiday_weekend_proximity() -> IndicatorSignature {
IndicatorSignature::builder("HOLIDAY_PROX", CATEGORY)
.name("Holiday & Weekend Proximity")
.description("Proximity to holidays and weekends")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::HolidayProx)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("HolidayProx")
.alias("holiday_prox")
.alias("HOLIDAY&WEEKENDPROXIMITY")
.alias("Holiday&WeekendProximity")
.alias("holiday&weekendproximity")
.alias("holiday_&_weekend_proximity")
.alias("HOLIDAY_&_WEEKEND_PROXIMITY")
.alias("Holiday_&_Weekend_Proximity")
.build()
}
pub fn signature_hour_of_day_effect() -> IndicatorSignature {
IndicatorSignature::builder("HOUR_DAY", CATEGORY)
.name("Hour of Day Effect")
.description("Hour of the day effect (0-23)")
.metadata("type", "temporal")
.metadata("category", "intraday")
.machine_id(BarIndicatorId::HourDay)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("HourDay")
.alias("hour_day")
.alias("HOUROFDAYEFFECT")
.alias("HourofDayEffect")
.alias("hourofdayeffect")
.alias("hour_of_day_effect")
.alias("HOUR_OF_DAY_EFFECT")
.alias("Hour_Of_Day_Effect")
.build()
}
pub fn signature_month_quarter_effect() -> IndicatorSignature {
IndicatorSignature::builder("MONTH_QTR", CATEGORY)
.name("Month & Quarter Effect")
.description("Month and quarter seasonality effects")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::MonthQtr)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("MonthQtr")
.alias("month_qtr")
.alias("MONTH&QUARTEREFFECT")
.alias("Month&QuarterEffect")
.alias("month&quartereffect")
.alias("month_&_quarter_effect")
.alias("MONTH_&_QUARTER_EFFECT")
.alias("Month_&_Quarter_Effect")
.build()
}
pub fn signature_month_turn_effect() -> IndicatorSignature {
IndicatorSignature::builder("MONTH_TURN", CATEGORY)
.name("Month Turn Effect")
.description("Turn of the month effect")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::MonthTurn)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("MonthTurn")
.alias("month_turn")
.alias("MONTHTURNEFFECT")
.alias("MonthTurnEffect")
.alias("monthturneffect")
.alias("month_turn_effect")
.alias("MONTH_TURN_EFFECT")
.alias("Month_Turn_Effect")
.build()
}
pub fn signature_quarter_turn_effect() -> IndicatorSignature {
IndicatorSignature::builder("QTR_TURN", CATEGORY)
.name("Quarter Turn Effect")
.description("Turn of the quarter effect")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::QtrTurn)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("QtrTurn")
.alias("qtr_turn")
.alias("QUARTERTURNEFFECT")
.alias("QuarterTurnEffect")
.alias("quarterturneffect")
.alias("quarter_turn_effect")
.alias("QUARTER_TURN_EFFECT")
.alias("Quarter_Turn_Effect")
.build()
}
pub fn signature_relative_trend_position() -> IndicatorSignature {
IndicatorSignature::builder("REL_TREND_POS", CATEGORY)
.name("Relative Trend Position")
.description("Relative position to SMA200 and anchored VWAP")
.add_constraint(ParamConstraint::period(50, 500, 200))
.metadata("type", "position")
.machine_id(BarIndicatorId::RelTrendPos)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Double)
.validated()
.alias("RelTrendPos")
.alias("rel_trend_pos")
.alias("RELATIVETRENDPOSITION")
.alias("RelativeTrendPosition")
.alias("relativetrendposition")
.alias("relative_trend_position")
.alias("RELATIVE_TREND_POSITION")
.alias("Relative_Trend_Position")
.build()
}
pub fn signature_session_effect() -> IndicatorSignature {
IndicatorSignature::builder("SESSION", CATEGORY)
.name("Session Effect")
.description("Trading session indicator")
.metadata("type", "temporal")
.metadata("category", "intraday")
.machine_id(BarIndicatorId::Session)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("Session")
.alias("session")
.alias("SESSIONEFFECT")
.alias("SessionEffect")
.alias("sessioneffect")
.alias("session_effect")
.alias("SESSION_EFFECT")
.alias("Session_Effect")
.build()
}
pub fn signature_start_end_of_month_flags() -> IndicatorSignature {
IndicatorSignature::builder("SOM_EOM", CATEGORY)
.name("Start/End of Month Flags")
.description("Binary flags for start and end of month")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::SomEom)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Double)
.validated()
.alias("SomEom")
.alias("som_eom")
.alias("STARTENDOFMONTHFLAGS")
.alias("StartEndofMonthFlags")
.alias("startendofmonthflags")
.alias("start_end_of_month_flags")
.alias("START_END_OF_MONTH_FLAGS")
.alias("Start_End_Of_Month_Flags")
.build()
}
pub fn signature_start_end_of_quarter_flags() -> IndicatorSignature {
IndicatorSignature::builder("SOQ_EOQ", CATEGORY)
.name("Start/End of Quarter Flags")
.description("Binary flags for start and end of quarter")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::SoqEoq)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Double)
.validated()
.alias("SoqEoq")
.alias("soq_eoq")
.alias("STARTENDOFQUARTERFLAGS")
.alias("StartEndofQuarterFlags")
.alias("startendofquarterflags")
.alias("start_end_of_quarter_flags")
.alias("START_END_OF_QUARTER_FLAGS")
.alias("Start_End_Of_Quarter_Flags")
.build()
}
pub fn signature_start_end_of_week_flags() -> IndicatorSignature {
IndicatorSignature::builder("SOW_EOW", CATEGORY)
.name("Start/End of Week Flags")
.description("Binary flags for start and end of week")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::SowEow)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Double)
.validated()
.alias("SowEow")
.alias("sow_eow")
.alias("STARTENDOFWEEKFLAGS")
.alias("StartEndofWeekFlags")
.alias("startendofweekflags")
.alias("start_end_of_week_flags")
.alias("START_END_OF_WEEK_FLAGS")
.alias("Start_End_Of_Week_Flags")
.build()
}
pub fn signature_week_in_month_effect() -> IndicatorSignature {
IndicatorSignature::builder("WEEK_MONTH", CATEGORY)
.name("Week in Month Effect")
.description("Week of the month effect (1-5)")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::WeekMonth)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("WeekMonth")
.alias("week_month")
.alias("WEEKINMONTHEFFECT")
.alias("WeekinMonthEffect")
.alias("weekinmontheffect")
.alias("week_in_month_effect")
.alias("WEEK_IN_MONTH_EFFECT")
.alias("Week_In_Month_Effect")
.build()
}
pub fn signature_weekday_effect() -> IndicatorSignature {
IndicatorSignature::builder("WEEKDAY", CATEGORY)
.name("Weekday Effect")
.description("Day of the week seasonality")
.metadata("type", "temporal")
.metadata("category", "calendar")
.machine_id(BarIndicatorId::Weekday)
.role_kind(IndicatorRoleKind::Other)
.output_kind(IndicatorValueKind::Single)
.validated()
.alias("Weekday")
.alias("weekday")
.alias("WEEKDAYEFFECT")
.alias("WeekdayEffect")
.alias("weekdayeffect")
.alias("weekday_effect")
.alias("WEEKDAY_EFFECT")
.alias("Weekday_Effect")
.build()
}
const BASE_CATALOG: &[(&str, fn() -> IndicatorSignature)] = &[
("AVWAP_DIST", signature_avwap_distance as fn() -> IndicatorSignature),
("VWAP_DIST", signature_vwap_distance as fn() -> IndicatorSignature),
("CPR", signature_central_pivot_range as fn() -> IndicatorSignature),
("DAY_WEEK_MONTH", signature_day_of_week_in_month as fn() -> IndicatorSignature),
("DOM_WOQ", signature_dayofmonth_weekofquarter_effect as fn() -> IndicatorSignature),
("DIST_LEVELS", signature_distance_to_levels as fn() -> IndicatorSignature),
("HOLIDAY_PROX", signature_holiday_weekend_proximity as fn() -> IndicatorSignature),
("HOUR_DAY", signature_hour_of_day_effect as fn() -> IndicatorSignature),
("MONTH_QTR", signature_month_quarter_effect as fn() -> IndicatorSignature),
("MONTH_TURN", signature_month_turn_effect as fn() -> IndicatorSignature),
("QTR_TURN", signature_quarter_turn_effect as fn() -> IndicatorSignature),
("REL_TREND_POS", signature_relative_trend_position as fn() -> IndicatorSignature),
("SESSION", signature_session_effect as fn() -> IndicatorSignature),
("SOM_EOM", signature_start_end_of_month_flags as fn() -> IndicatorSignature),
("SOQ_EOQ", signature_start_end_of_quarter_flags as fn() -> IndicatorSignature),
("SOW_EOW", signature_start_end_of_week_flags as fn() -> IndicatorSignature),
("WEEK_MONTH", signature_week_in_month_effect as fn() -> IndicatorSignature),
("WEEKDAY", signature_weekday_effect as fn() -> IndicatorSignature),
];
pub static POSITION_CATALOG: Lazy<HashMap<String, fn() -> IndicatorSignature>> = Lazy::new(|| {
let mut m = HashMap::new();
for &(main_id, func) in BASE_CATALOG {
let sig = func();
m.insert(main_id.to_string(), func);
for alias in &sig.aliases {
m.insert(alias.clone(), func);
}
}
m
});
pub fn get_signature(id: &str) -> Option<IndicatorSignature> {
POSITION_CATALOG.get(id).map(|f| f())
}
pub fn all_indicator_ids() -> Vec<&'static str> {
BASE_CATALOG.iter().map(|(id, _)| *id).collect()
}
pub fn count() -> usize {
BASE_CATALOG.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_count() {
assert_eq!(count(), 18); }
#[test]
fn test_all_signatures_valid() {
for id in all_indicator_ids() {
let sig = get_signature(id).unwrap();
assert_eq!(sig.id, id);
assert_eq!(sig.category, CATEGORY);
}
}
}