1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! US 30/360 with an explicit security end-of-month qualification.
use ;
use crateDate;
/// US 30/360 with the security's end-of-month qualification supplied explicitly.
///
/// This local definition follows the four ordered adjustments in the FIX
/// column of [ROC Revised CDE Technical Guidance v4 (December 2025), Table 4,
/// A001, printed p.166](https://www.leiroc.org/publications/gls/Final_ROC202531-Revised-CDE-Technical-Guidance-Version-4.pdf#page=157).
/// It pins that reporting definition; the complete SIA/SIFMA book definition
/// remains uninspected, and other columns or instruments may use different
/// February treatment. See the [adopted local contract](https://github.com/iceman951/sabiquant/blob/main/docs/M3_US_AFB_CONTRACT.md).
///
/// On an increasing interval, the explicit flag enables two adjustments:
/// change the ending day to 30 when both original dates are February month
/// ends, then change a February-month-end starting day to 30. Next, change an
/// ending 31st to 30 when the current starting day is 30 or 31; finally change
/// a starting 31st to 30. Divide `360ΔY + 30ΔM + D′end − D′start` by 360.
/// Disabling the flag gives the existing Bond Basis arithmetic.
///
/// The flag is a security property, never inferred from dates, schedules or
/// calendar month-end advancement. There is no default constructor or
/// context-free text parser. Reversed dates negate the chronological forward
/// result while retaining the same flag; every zero result is positive zero.
/// All operations take constant time across [`Date::MIN`] to [`Date::MAX`].
///
/// QuantLib 1.43's `Thirty360(USA)` has no corresponding explicit flag: its
/// forward formula matches the enabled setting. SabiQuant's chronological
/// normalization can differ from applying a directional formula backwards.
/// Agreement with a reference does not determine a security's qualification.
///
/// ```
/// use sabiquant::daycount::Thirty360Us;
/// use sabiquant::time::Date;
///
/// let start = Date::from_ymd(2023, 2, 28)?;
/// let end = Date::from_ymd(2023, 3, 31)?;
/// let end_of_month = Thirty360Us::new(true);
/// let other = Thirty360Us::new(false);
/// assert!(end_of_month.end_of_month_security());
/// assert!(!other.end_of_month_security());
/// assert_eq!(end_of_month.day_count(start, end), 30);
/// assert_eq!(other.day_count(start, end), 33);
/// assert_eq!(end_of_month.year_fraction(start, end)?.to_bits(), (30.0_f64 / 360.0).to_bits());
/// assert_eq!(other.year_fraction(start, end)?.to_bits(), (33.0_f64 / 360.0).to_bits());
/// # Ok::<(), sabiquant::error::Error>(())
/// ```