Skip to content

Commit e76400d

Browse files
committed
~ compile code and publish to npm
1 parent 90445d1 commit e76400d

File tree

10 files changed

+399
-22
lines changed

10 files changed

+399
-22
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
lib
2-
dist
32
node_modules
43
data

.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
src
2+
data
3+
hst_parser.png

README.md

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,115 @@ Parser for the MetaTrader History (.hst) File Format in Node.js
1010

1111
* [Summary](#)
1212
* [Table of Contents](#)
13-
* [Installation](#)
13+
* [Installation](#)
1414
* [Usage](#)
1515
* [Author](#)
1616
* [Thank You](#)
1717
* [Licence](#)
1818

19+
### Installation
20+
21+
```sh
22+
npm install hst-parser --save
23+
# or
24+
yarn add hst-parser
25+
# or
26+
bower install hst-parser --save
27+
```
28+
1929
### Usage
2030

31+
```javascript
32+
const HSTReader = require('hst-parser').HSTReader;
33+
34+
const tradeHistory = new HSTReader('./data/USDGBP.hst'); // your .hst file
35+
```
36+
37+
38+
#### Variables
39+
the HSTReader class exposes some variables for you to use
40+
```javascript
41+
console.log(tradeHistory.version); // file version from headers
42+
// example output: 400
43+
44+
console.log(tradeHistory.symbol); // the symbol / ticker / currency pair from the file
45+
// example output: "USDGBP"
46+
47+
console.log(tradeHistory.period); // the interval (in minutes) of the data
48+
// example output: 1
49+
50+
console.log(tradeHistory.start); // the JS Date of the first candle
51+
// example output: Tue Nov 05 1985 00:52:00 GMT+0000 (GMT)
52+
53+
console.log(tradeHistory.candleNumber); // the number of the last read candle
54+
// example output: 12345
55+
56+
console.log(tradeHistory.endOfFile); // true or false, has the parser hit the end of the file?
57+
// example output: false
58+
```
59+
60+
#### Candle
61+
62+
Candles are a section of data at any given interval.
63+
64+
Example:
65+
```json
66+
{
67+
"close": 90.26,
68+
"high": 90.27,
69+
"low": 90.25,
70+
"open": 90.27,
71+
"realVolume": 0,
72+
"spread": 0,
73+
"timestamp": "2010-01-26T00:00:00.000Z",
74+
"volume": 9
75+
}
76+
```
77+
78+
#### isValidFormat()
79+
80+
Checks if file can be parsed by HSTReader. (currently supports versions 400 and 401 of .hst files)
81+
```javascript
82+
if(tradeHistory.isValidFormat()) {
83+
// do stuff
84+
} else {
85+
// error?
86+
}
87+
```
88+
89+
#### getCandleNumber(candleNumber)
90+
91+
Returns candle data at specified position
92+
```javascript
93+
console.log(tradeHistory.getCandleNumber(200));
94+
// output: {Candle}
95+
```
96+
97+
#### getNextCandle()
98+
99+
Returns next set of candle data
100+
```javascript
101+
console.log(tradeHistory.getNextCandle());
102+
// output: {Candle}
103+
```
104+
105+
#### getPrevCandle()
106+
107+
Returns previous set of candle data
108+
```javascript
109+
console.log(tradeHistory.getPrevCandle());
110+
// output: {Candle}
111+
```
112+
113+
#### getCandleAt(date, ...[startDate, i])
114+
115+
Returns set of candle data at specified date and time
116+
```javascript
117+
const myBirthday = new Date(1996, 0, 26);
118+
console.log(tradeHistory.getCandleAt(myBirthday));
119+
// output: {Candle}
120+
```
121+
21122
### Author
22123

23124
Kyron Taylor (gitbugr)

dist/hst_reader.d.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Candle from "./interfaces/candle";
2+
export default class HSTReader {
3+
version: number;
4+
symbol: string;
5+
period: number;
6+
start: Date;
7+
candleNumber: number;
8+
endOfFile: boolean;
9+
private fd;
10+
private byteOffset;
11+
private candleByteSize;
12+
private filesize;
13+
/**
14+
* @param {string} filename Reads headers of specified file and stores into class variables.
15+
*/
16+
constructor(filename: string);
17+
/**
18+
* @return {boolean} checks if parser supports file version
19+
*/
20+
isValidFormat(): boolean;
21+
/**
22+
* @return {Candle} returns the next candle in the file
23+
*/
24+
getNextCandle(): Candle;
25+
/**
26+
* @return {Candle} returns the previous candle in the file
27+
*/
28+
getPrevCandle(): Candle;
29+
/**
30+
* @param {number} candleNumber finds candle from number
31+
* @return {Candle} returns specified candle
32+
*/
33+
getCandleNumber(candleNumber: number): Candle;
34+
/**
35+
* @param {Date} date finds candle at specified date and time
36+
* @param {Date=} startDate optional: due to missing candles, we try to find based on most likely position
37+
* @param {number=} i optional: count attempts to limit search area
38+
* @return {Candle} returns the candle if found
39+
*/
40+
getCandleAt(date: Date, startDate?: Date, i?: number): Candle;
41+
/**
42+
* @return {Candle} returns candle at byte position
43+
*/
44+
private readCandle;
45+
}

dist/hst_reader.js

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"use strict";
2+
var __importStar = (this && this.__importStar) || function (mod) {
3+
if (mod && mod.__esModule) return mod;
4+
var result = {};
5+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
6+
result["default"] = mod;
7+
return result;
8+
};
9+
var __importDefault = (this && this.__importDefault) || function (mod) {
10+
return (mod && mod.__esModule) ? mod : { "default": mod };
11+
};
12+
Object.defineProperty(exports, "__esModule", { value: true });
13+
// packages
14+
const fs = __importStar(require("fs"));
15+
// parser dataa
16+
const parser_data_1 = __importDefault(require("./parser_data"));
17+
class HSTReader {
18+
/**
19+
* @param {string} filename Reads headers of specified file and stores into class variables.
20+
*/
21+
constructor(filename) {
22+
// check if file exists
23+
if (!fs.existsSync(filename)) {
24+
throw new Error(`Can't find this file: ${filename}`);
25+
}
26+
// open file and store file descriptor as variable
27+
this.fd = fs.openSync(filename, 'r');
28+
// verify filesize is larger than header size
29+
this.filesize = fs.statSync(filename).size;
30+
if (this.filesize < 148) {
31+
throw new Error(`Damn, that's a small file. Too small.`);
32+
}
33+
// set up buffers
34+
const version = Buffer.alloc(4);
35+
const symbol = Buffer.alloc(12);
36+
const period = Buffer.alloc(4);
37+
const start = Buffer.alloc(4);
38+
// scoped byte offset
39+
let byteOffset = 0;
40+
// read version number
41+
fs.readSync(this.fd, version, 0, 4, byteOffset);
42+
// read into symbol buffer (skip copyright header [+64 bytes])
43+
fs.readSync(this.fd, symbol, 0, 12, byteOffset += 64 + 4);
44+
// read period
45+
fs.readSync(this.fd, period, 0, 4, byteOffset += 12);
46+
// read start date from first candle
47+
fs.readSync(this.fd, start, 0, 4, 148);
48+
// convert to js types and store in class variables
49+
this.version = version.readInt32LE(0);
50+
this.symbol = symbol.toString("utf8");
51+
this.period = period.readInt32LE(0);
52+
this.start = new Date(start.readInt32LE(0) * 1000);
53+
this.endOfFile = false;
54+
// set byte offset to end of header-block
55+
this.candleByteSize = this.version === 400 ? 44 : 60;
56+
this.byteOffset = 148 - this.candleByteSize;
57+
this.candleNumber = 0;
58+
}
59+
/**
60+
* @return {boolean} checks if parser supports file version
61+
*/
62+
isValidFormat() {
63+
return Object.keys(parser_data_1.default).indexOf(this.version.toString()) !== -1;
64+
}
65+
/**
66+
* @return {Candle} returns the next candle in the file
67+
*/
68+
getNextCandle() {
69+
if (this.byteOffset + this.candleByteSize <= this.filesize) {
70+
this.byteOffset += this.candleByteSize;
71+
this.candleNumber += 1;
72+
this.endOfFile = false;
73+
}
74+
else {
75+
this.endOfFile = true;
76+
}
77+
return this.readCandle();
78+
}
79+
/**
80+
* @return {Candle} returns the previous candle in the file
81+
*/
82+
getPrevCandle() {
83+
if (this.byteOffset - this.candleByteSize >= 148) {
84+
this.byteOffset -= this.candleByteSize;
85+
this.candleNumber -= 1;
86+
this.endOfFile = false;
87+
}
88+
return this.readCandle();
89+
}
90+
/**
91+
* @param {number} candleNumber finds candle from number
92+
* @return {Candle} returns specified candle
93+
*/
94+
getCandleNumber(candleNumber) {
95+
this.candleNumber = candleNumber;
96+
this.byteOffset = 148 + (candleNumber * this.candleByteSize);
97+
return this.readCandle();
98+
}
99+
/**
100+
* @param {Date} date finds candle at specified date and time
101+
* @param {Date=} startDate optional: due to missing candles, we try to find based on most likely position
102+
* @param {number=} i optional: count attempts to limit search area
103+
* @return {Candle} returns the candle if found
104+
*/
105+
getCandleAt(date, startDate = this.start, i = 0) {
106+
const candleOffset = (date.getTime() - startDate.getTime()) / (60000 * this.period);
107+
let candle = this.getCandleNumber(this.candleNumber + candleOffset);
108+
if (candle.timestamp.getTime() == date.getTime()) {
109+
return candle;
110+
}
111+
else if (i < 50 && candle.timestamp.getTime()) {
112+
return this.getCandleAt(date, candle.timestamp, i + 1);
113+
}
114+
else if (i < 50) {
115+
candle = this.getCandleNumber(Math.floor(this.candleNumber / 2));
116+
return this.getCandleAt(date, candle.timestamp, i + 1);
117+
}
118+
else {
119+
throw new Error("Could not find candle");
120+
}
121+
}
122+
/**
123+
* @return {Candle} returns candle at byte position
124+
*/
125+
readCandle() {
126+
if (this.byteOffset < 148) {
127+
this.byteOffset = 148;
128+
}
129+
const parserFunctions = {
130+
date: (buffer) => {
131+
let timestamp = buffer.readInt32LE(0);
132+
timestamp = timestamp < 9999999999 ? timestamp * 1000 : timestamp;
133+
return new Date(timestamp);
134+
},
135+
double: (buffer) => buffer.readDoubleLE(0),
136+
i32: (buffer) => buffer.readInt32LE(0),
137+
undefined: (buffer) => undefined,
138+
};
139+
const candleData = {};
140+
Object.entries(parser_data_1.default[this.version]).forEach(([key, data]) => {
141+
if (typeof data.value !== "undefined") {
142+
candleData[key] = data.value;
143+
}
144+
else {
145+
candleData[key] = Buffer.alloc(data.size || 0);
146+
fs.readSync(this.fd, candleData[key], 0, data.size || 0, this.byteOffset + (data.position || 0));
147+
candleData[key] = parserFunctions[data.type || "undefined"](candleData[key]);
148+
}
149+
});
150+
return candleData;
151+
}
152+
}
153+
exports.default = HSTReader;
154+
module.exports = {
155+
HSTReader,
156+
};

dist/parser_data.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import parserDataInterface from "./interfaces/parser_data";
2+
declare const parserData: parserDataInterface;
3+
export default parserData;

0 commit comments

Comments
 (0)