Use your own calendar
You'll get a business-day calendar the shipped data doesn't carry: a shipped one with an extra closure, one you build outright with its own weekend, or one you ingest under a code so every later lookup reads it.
Before you start
- helixio installed, in Rust or Python: see installing.
- The closures you need, as dates. For a calendar you build outright, its weekend days too.
Steps
- To add a closure to a shipped calendar, call
amendedon it with the closing dates. You get a new calendar; the shipped one is unchanged. - To build a calendar outright, give
Calendar.from_holidaysa name, the closures and the weekend days (in Rust,DataCalendar::newwith a weekend mask indexed from Monday). - To make a code answer everywhere in the process, ingest it with
ingest_calendars. From then onCalendar("XDSK")and joint expressions such as"XDSK,USNY"read it. Ingest before you draft trades: a trade drafted earlier keeps its dates.
The comments in the program match these steps.
Rust
use std::collections::HashSet;
use chrono::{Datelike, Duration, NaiveDate, Weekday};
use helixrs::{Calendar, CalendarSpec, DataCalendar, amended, calendar, ingest_calendars, ingested_calendars};
fn date(year: i32, month: u32, day: u32) -> NaiveDate {
NaiveDate::from_ymd_opt(year, month, day).expect("a real calendar date")
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let new_york = calendar("USNY")?;
let year_start = date(2031, 1, 1);
let year_end = date(2032, 1, 1);
let closure = date(2031, 7, 3);
// Amend a shipped calendar with a closure it does not carry. Calendars are
// never edited: you get a new one, and New York itself is unchanged.
let derived = amended(new_york.as_ref(), &[closure], &[])?;
let shipped_days = new_york.business_days_between(year_start, year_end);
let amended_days = derived.business_days_between(year_start, year_end);
let open = |c: &dyn Calendar| if c.is_business_day(closure) { "open" } else { "closed" };
println!("{closure} in {:<14} {}", derived.name(), open(derived.as_ref()));
println!("{closure} in {:<14} {}", new_york.name(), open(new_york.as_ref()));
println!("open days in 2031: {amended_days} amended, {shipped_days} shipped");
// Build a calendar outright, here with a Friday-Saturday weekend and one
// closure. The weekend mask is indexed from Monday.
let mut weekmask = [false; 7];
weekmask[Weekday::Fri.num_days_from_monday() as usize] = true;
weekmask[Weekday::Sat.num_days_from_monday() as usize] = true;
let desk = DataCalendar::new("DESK", HashSet::from([date(2031, 3, 20)]), weekmask);
let desk_next = desk.next_business_day(date(2031, 3, 20));
println!(
"DESK: after its 2031-03-20 closure, next open day {desk_next} ({})",
desk_next.format("%a")
);
// Ingest a calendar under a code. From then on every lookup of that code in
// the process reads it, alone or joined with a shipped centre.
ingest_calendars(&[CalendarSpec::new("XDSK", vec![date(2031, 3, 20)])])?;
let ingested_days = calendar("XDSK")?.business_days_between(year_start, year_end);
let joined_days = calendar("XDSK,USNY")?.business_days_between(year_start, year_end);
println!("XDSK open days in 2031 {ingested_days}");
println!("XDSK,USNY open days in 2031 {joined_days}");
println!("ingested codes {}", ingested_calendars().join(", "));
Ok(())
}Python
import datetime as dt
import helixio as hlx
NEW_YORK = hlx.Calendar("USNY")
YEAR_START = dt.date(2031, 1, 1)
YEAR_END = dt.date(2032, 1, 1)
CLOSURE = dt.date(2031, 7, 3)
# Amend a shipped calendar with a closure it does not carry. Calendars are
# never edited: you get a new one, and New York itself is unchanged.
amended = NEW_YORK.amended(closing=[CLOSURE])
shipped_days = NEW_YORK.business_days_between(YEAR_START, YEAR_END)
amended_days = amended.business_days_between(YEAR_START, YEAR_END)
print(f"{CLOSURE} in {amended.name():<14} {'open' if amended.is_business_day(CLOSURE) else 'closed'}")
print(f"{CLOSURE} in {NEW_YORK.name():<14} {'open' if NEW_YORK.is_business_day(CLOSURE) else 'closed'}")
print(f"open days in 2031: {amended_days} amended, {shipped_days} shipped")
# Build a calendar outright, here with a Friday-Saturday weekend and one closure.
desk = hlx.Calendar.from_holidays("DESK", [dt.date(2031, 3, 20)], ["Friday", "Saturday"])
desk_next = desk.next_business_day(dt.date(2031, 3, 20))
print(f"DESK: after its 2031-03-20 closure, next open day {desk_next} ({desk_next.strftime('%a')})")
# Ingest a calendar under a code. From then on every lookup of that code in the
# process reads it, alone or joined with a shipped centre.
hlx.dates.ingest_calendars([hlx.dates.CalendarSpec("XDSK", [dt.date(2031, 3, 20)])])
ingested_days = hlx.Calendar("XDSK").business_days_between(YEAR_START, YEAR_END)
joined_days = hlx.Calendar("XDSK,USNY").business_days_between(YEAR_START, YEAR_END)
print(f"XDSK open days in 2031 {ingested_days}")
print(f"XDSK,USNY open days in 2031 {joined_days}")
print(f"ingested codes {', '.join(hlx.dates.ingested_calendars())}")2031-07-03 in <USNY amended> closed
2031-07-03 in USNY open
open days in 2031: 249 amended, 250 shipped
DESK: after its 2031-03-20 closure, next open day 2031-03-23 (Sun)
XDSK open days in 2031 260
XDSK,USNY open days in 2031 249
ingested codes XDSK
Check it worked
- The amended calendar is closed on the day you named, and the shipped one is still open.
- The year loses exactly one open day per closure you added.
- The built calendar treats its own weekend days as closed, and the next open day after its closure respects that weekend.
ingested_calendars()lists your code.
Related
- Calendars, the reference for every calendar method.
- Dates and periods, for advancing by tenors on a calendar.
From the 0.0 line at revision bf7f2e2. Every printed number is that revision's own output.