fme-free-barchart
Version:
API for fetching data from the Free Barchart API
185 lines (151 loc) • 6.38 kB
text/typescript
import {Log} from "fme-logger";
var L = new Log("FreeBarchart");
import * as _m from "moment-timezone";
import * as request from "request-promise-native";
import {FmeQuote} from "fme-quotes-models";
interface EsQuote {
}
interface History {
}
function convert (x:any,type:string,interval:number) {
var obj = new FmeQuote();
obj.symbol = x.symbol.toUpperCase();
obj.YYYYMMDD = _m(x.timestamp).format("YYYYMMDD");
obj.timeHHMM = _m(x.timestamp).format("HHmm");
obj.time = _m(x.timestamp).hours()*60+_m(x.timestamp).minutes();
obj.timestamp = x.timestamp;
obj.open = x.open;
obj.close = x.close;
obj.high = x.high;
obj.low = x.low;
obj.avg = (x.open+x.close+x.high+x.low)/4;
obj.volume = x.volume;
obj.source = "barchart-free";
obj.decimalPoints = 2;
obj.interval = interval;
obj.type = type;
return obj
}
export class FreeBarchart {
version = "1.0.0";
host = "marketdata.websol.barchart.com";
endpoint = "getHistory.json";
// symbol = "ES*1";
symbol = "SPY";
type = "minutes";
types = ["ticks", "minutes", "nearbyMinutes", "formTMinutes", "daily", "dailyNearest", "dailyContinue", "weekly", "weeklyNearest",
"weeklyContinue", "monthly", "monthlyNearest", "monthlyContinue", "quarterly", "quarterlyNearest", "quarterlyContinue", "yearly",
"yearlyNearest", "yearlyContinue"];
typesSingleDay = ["ticks","minutes","nearbyMinutes","formTMinutes"];
interval = 1;
startTime = 9*60 + 30; // default startTime == 9:30;
endTime = 16*60 + 0; // default endTime = 4pm;
targetDate = new Date();
//
// @KEY = FREE BARCHART KEY STRING
// @SYMBOL = BARCHART SYMBOL
// @FRAME = TIMEFRAME = "minute","day","week"
// @Interval = number (1,2,3) (combines with FRAME to complete the reqeust);
//
constructor(private key:string,symbol:string,frame:string,interval:number,targetDate:Date,startTime?:number,endTime?:number) {
this.symbol = symbol;
//
// => convert futures contract to dated contract based on target date
//
if (this.symbol.toLowerCase().indexOf("_f")> -1) {
var contract = new ContractConversion()
var expiry = 3;
if (symbol.toLowerCase().indexOf("cl")> -1) expiry = 1;
this.symbol = this.symbol.toLowerCase().replace("_f",contract.findCode(targetDate,expiry))
}
this.type = frame.toLowerCase().trim();
if (startTime) this.startTime == startTime;
if (endTime) this.endTime == endTime;
this.targetDate = targetDate;
if (this.types.indexOf(this.type) == -1 ) {
L.error("Invalid type passed",this.types,"valid types are",JSON.stringify(this.types))
return;
}
if (!interval) this.interval = 1; else this.interval = interval;;
}
getDailyMinutes = async () => {
var type = this.type.trim().toLowerCase();
var symbol = this.symbol.trim().toLowerCase();
var startDate = _m(this.targetDate).format("YYYYMMDD");
var req = "/"+this.endpoint+"?key="+this.key+"&symbol="+this.symbol+"&type="+type+"&startDate="+startDate+"&interval="+this.interval;
var fullUrl = "http://"+this.host+req;
L.info("requesting:",fullUrl);
try {
var results = await request(fullUrl)
var rtn = JSON.parse(results).results;
if (!rtn) {
L.info("barchart did not return a value for date",startDate)
return null;
}
}catch(err) {
L.error(err,results);
return
}
L.info("Rtn is",rtn.length,rtn[rtn.length-1]);
var filter:FmeQuote[] = [];
if (this.typesSingleDay.indexOf(type) > -1) {
filter = rtn.filter((x:any) =>{return _m(x.timestamp).format("YYYYMMDD") == startDate } ).map((a:any)=>{ return convert(a,type,this.interval)} ) as FmeQuote[];
} else {
filter = rtn.filter.map((a:any)=>{ return convert(a,type,this.interval)} ) as FmeQuote[];
}
// L.info("filter length is",filter.length,filter[0],filter[filter.length-1]);
// return filter.filter((a) => {return a.time >= this.startTime && a.time <= this.endTime});
return filter.map( (a:any) => {return convert(a,type,this.interval)} )
}
}
export class Conversion {
inputSymbol:string = "SPY";
symbol: string = "spy";
exchange: string = "nyse";
timeAdjust?:number = 0;
expiryLength? = 3
}
export class ContractConversion {
codes = ["F","G","H","J","K","M","N","Q","U","V","X","Z"];
rollOffset = 8 ; // number of days offset from expiration the roll is.
//
// => find codes
// Date: date to find code for
// Length: Number of Months between contract roll, only supports monthly (1) or quarterly(3);
//
findCode = (date:Date,length:number) => {
if (length == 1) {
if (_m(date).date() > 20) offset = 2;
else offset = 2;
var month = _m(date).month()+offset;
return this.codes[month]+_m(date).format("YY");
}
if(length == 3) {
var quarter = _m(date).quarter();; // quarter to find contract
L.info("We are in this quarter",quarter);
//
// add either 2 or 5 to this number to get the contract
// add 2 if the current date is before the expiration + rolloffset, else add 3.
//
var startOfMonth = _m(date).startOf("quarter").add(2,"months").clone();
var today = startOfMonth.day();
if (today == 6) var inc = 3
else inc = 2;
var expiration = startOfMonth.day(5).add(inc,"weeks");
var rollover = expiration.clone().subtract(this.rollOffset,"days");
L.info("Date",_m(date).format("YYYYMMDD"),"rollover",rollover.format("YYYYMMDD"));
if ( date >= rollover.toDate()) var offset = quarter*3+2;
else offset=quarter*3-1;
//
// => take care of annual roll at the end of the year!
//
var annualOffset = 0;
if (offset > 11) {
offset = offset - 12;
annualOffset = 1;
}
L.info("expiration is",expiration.format("YYYYMMDD"),"roll over is",rollover.format("YYYYMMDD"),"offset is",offset)
return this.codes[offset]+_m(date).add(annualOffset,"years").format("YY");
}
}
}