8
8
"github.com/quick-trade/xoney/internal"
9
9
)
10
10
11
+ // Period is a utility structure used for denoting intervals in time.
12
+ // It allows for convenient slicing of various time-series data.
11
13
type Period struct {
12
14
Start time.Time
13
15
End time.Time
@@ -17,12 +19,17 @@ func NewPeriod(start, end time.Time) Period {
17
19
return Period {Start : start , End : end }
18
20
}
19
21
22
+ // ShiftedStart returns a new Period with the start time shifted by the given duration.
23
+ // The end time of the Period is not affected.
20
24
func (p Period ) ShiftedStart (shift time.Duration ) Period {
21
25
p .Start = p .Start .Add (shift )
22
26
23
27
return p
24
28
}
25
29
30
+ // TimeStamp represents a sequence of time moments.
31
+ // These moments are not required to have a constant step between them,
32
+ // but the data should be sequential.
26
33
type TimeStamp struct {
27
34
timeframe TimeFrame
28
35
Timestamp []time.Time
@@ -38,11 +45,13 @@ func NewTimeStamp(timeframe TimeFrame, capacity int) TimeStamp {
38
45
func (t * TimeStamp ) Timeframe () TimeFrame {
39
46
return t .timeframe
40
47
}
41
-
48
+ // At returns the time at the specified index within the TimeStamp.
42
49
func (t TimeStamp ) At (index int ) time.Time {
43
50
return t .Timestamp [index ]
44
51
}
45
52
53
+ // Extend increases the length of the TimeStamp by n timeframes,
54
+ // adding new moments sequentially based on the TimeStamp's timeframe.
46
55
func (t * TimeStamp ) Extend (n int ) {
47
56
last := t .At (len (t .Timestamp ) - 1 )
48
57
for i := 0 ; i < n ; i ++ {
@@ -51,26 +60,36 @@ func (t *TimeStamp) Extend(n int) {
51
60
}
52
61
}
53
62
63
+ // Append adds the provided moments to the end of the TimeStamp.
64
+ // If you need to extend the TimeStamp by N timeframes, consider using Extend instead.
54
65
func (t * TimeStamp ) Append (moments ... time.Time ) {
55
66
t .Timestamp = internal .Append (t .Timestamp , moments ... )
56
67
}
57
68
69
+ // Slice returns a new TimeStamp consisting of the time moments within the range [start, stop).
58
70
func (t TimeStamp ) Slice (start , stop int ) TimeStamp {
59
71
return TimeStamp {
60
72
timeframe : t .timeframe ,
61
73
Timestamp : t .Timestamp [start :stop ],
62
74
}
63
75
}
64
76
77
+ // End returns the last time moment within the TimeStamp.
65
78
func (t TimeStamp ) End () time.Time {
66
79
return t .At (len (t .Timestamp ) - 1 )
67
80
}
68
81
82
+ // Start returns the first time moment within the TimeStamp.
69
83
func (t TimeStamp ) Start () time.Time {
70
84
return t .At (0 )
71
85
}
86
+
87
+ // Len returns the number of time moments within the TimeStamp.
72
88
func (t TimeStamp ) Len () int { return len (t .Timestamp ) }
73
89
90
+ // Candle represents a single candlestick data point in a financial chart,
91
+ // encapsulating the open, high, low, close values and the volume of trading
92
+ // over a particular time period, with TimeClose marking the end of that period.
74
93
type Candle struct {
75
94
Open float64
76
95
High float64
@@ -90,7 +109,10 @@ func NewCandle(open, high, low, c, volume float64, timeClose time.Time) *Candle
90
109
TimeClose : timeClose ,
91
110
}
92
111
}
93
-
112
+ // InstrumentCandle represents a candlestick data point with an associated financial instrument.
113
+ // It combines the detailed candlestick information such as OHLCV with the specific instrument
114
+ // for which this data is relevant. This data structure is commonly used in trading strategies
115
+ // as the primary source of information from which trading signals are generated.
94
116
type InstrumentCandle struct {
95
117
Candle
96
118
Instrument
@@ -103,6 +125,9 @@ func NewInstrumentCandle(candle Candle, instrument Instrument) *InstrumentCandle
103
125
}
104
126
}
105
127
128
+ // Chart represents a sequence of candlestick data points for a specific instrument.
129
+ // It contains slices of open, high, low, close values and the trading volume,
130
+ // along with the corresponding timestamps for each data point.
106
131
type Chart struct {
107
132
Open []float64
108
133
High []float64
@@ -112,6 +137,9 @@ type Chart struct {
112
137
Timestamp TimeStamp
113
138
}
114
139
140
+ // RawChart creates a new Chart with slices preallocated to the specified capacity.
141
+ // This function is used to initialize a Chart for a certain timeframe and with a capacity
142
+ // hint to optimize memory allocations for the underlying slices.
115
143
func RawChart (timeframe TimeFrame , capacity int ) Chart {
116
144
return Chart {
117
145
Open : make ([]float64 , 0 , capacity ),
@@ -123,6 +151,9 @@ func RawChart(timeframe TimeFrame, capacity int) Chart {
123
151
}
124
152
}
125
153
154
+ // Add appends a single candle to the end of the chart.
155
+ // It appends the open, high, low, close, and volume data from the candle
156
+ // to their respective slices in the Chart and updates the timestamp.
126
157
func (c * Chart ) Add (candle Candle ) {
127
158
c .Open = internal .Append (c .Open , candle .Open )
128
159
c .High = internal .Append (c .High , candle .High )
@@ -132,6 +163,10 @@ func (c *Chart) Add(candle Candle) {
132
163
c .Timestamp .Append (candle .TimeClose )
133
164
}
134
165
166
+ // Slice returns a new Chart consisting of the candlestick data within the specified period.
167
+ // It performs a binary search to find the start and end indices, ensuring O(log N) complexity.
168
+ // The resulting slice includes the boundaries of the period. If an exact match for the boundaries
169
+ // is not found, the nearest preceding element is included in the slice.
135
170
func (c * Chart ) Slice (period Period ) Chart {
136
171
start , err := findIndexBeforeOrAtTime (c .Timestamp , period .Start )
137
172
if err != nil {
@@ -152,11 +187,18 @@ func (c *Chart) Slice(period Period) Chart {
152
187
Timestamp : c .Timestamp .Slice (start , stop ),
153
188
}
154
189
}
155
-
190
+ // Len returns the number of timestamps (and hence the number of candles) in the Chart.
156
191
func (c * Chart ) Len () int {
157
192
return len (c .Timestamp .Timestamp )
158
193
}
159
194
195
+ // CandleByIndex retrieves the candle at the specified index from the Chart.
196
+ // If the index is out of range, an error is returned.
197
+ // Parameters:
198
+ // index - The index of the candle to retrieve.
199
+ // Returns:
200
+ // pointer to a Candle and nil error if successful, or
201
+ // nil pointer and an OutOfIndexError if the index is invalid.
160
202
func (c * Chart ) CandleByIndex (index int ) (* Candle , error ) {
161
203
if index >= c .Len () {
162
204
return nil , errors .NewOutOfIndexError (index )
@@ -171,9 +213,12 @@ func (c *Chart) CandleByIndex(index int) (*Candle, error) {
171
213
c .Timestamp .At (index ),
172
214
), nil
173
215
}
174
-
216
+ // ChartContainer represents a collection of instruments and their corresponding charts.
217
+ // It can be used to inform your trading system about your investment universe during testing and training.
175
218
type ChartContainer map [Instrument ]Chart
176
219
220
+ // ChartsByPeriod slices each chart in the ChartContainer to a new chart based on the provided period.
221
+ // It's analogous to the Slice method of the Chart, but it operates on the entire container, slicing each chart.
177
222
func (c * ChartContainer ) ChartsByPeriod (period Period ) ChartContainer {
178
223
result := make (ChartContainer , len (* c ))
179
224
for instrument , chart := range * c {
@@ -183,6 +228,9 @@ func (c *ChartContainer) ChartsByPeriod(period Period) ChartContainer {
183
228
return result
184
229
}
185
230
231
+ // FirstStart finds the earliest start time among all charts in the ChartContainer.
232
+ // It iterates through all charts and returns the earliest timestamp found.
233
+ // If the ChartContainer is empty, it returns the zero value of time.Time.
186
234
func (c * ChartContainer ) FirstStart () time.Time {
187
235
var first time.Time
188
236
@@ -196,6 +244,9 @@ func (c *ChartContainer) FirstStart() time.Time {
196
244
return first
197
245
}
198
246
247
+ // LastEnd finds the latest end time among all charts in the ChartContainer.
248
+ // It iterates through all charts and returns the latest timestamp found.
249
+ // If the ChartContainer is empty, it returns the zero value of time.Time.
199
250
func (c * ChartContainer ) LastEnd () time.Time {
200
251
var last time.Time
201
252
@@ -226,6 +277,9 @@ func (c *ChartContainer) sortedInstruments() []Instrument {
226
277
return keys
227
278
}
228
279
280
+ // Candles returns all the candles in the ChartContainer.
281
+ // It implements a merging stage of the merge-sort algorithm.
282
+ // Complexity: O(NK), where N is the number of candles and K is the number of instruments.
229
283
func (c ChartContainer ) Candles () []InstrumentCandle {
230
284
// It is just merging from merge-sort algorithm
231
285
sumLength := 0
0 commit comments