star
Version:
A STock Analysis and Research tool for terminal users.
180 lines (144 loc) • 7.84 kB
JavaScript
/**
* @author hustcer
* @license MIT
* @copyright uzfin.com
* @create 05/18/2015
*/
;
let _ = require('lodash'),
colors = require('colors'),
Promise = require('bluebird'),
cmd = require('commander');
const pkg = require('./package.json');
let conf = require('./lib/conf').conf;
let action = null; // cmd action
/**
* Available colors are:
* bold, italic, underline, inverse, yellow, cyan, white,
* green, red, grey, blue, rainbow, zebra, random, magenta,
*/
const COLOR_THEME = {
error : 'red',
info : 'blue',
data : 'grey',
header : 'blue',
warn : 'yellow',
em : 'magenta',
};
colors.setTheme(COLOR_THEME);
// Fix Issue: https://github.com/tj/commander.js/issues/530
// For Node v6.0.0 and v6.1.0; TODO: remove it later
[process.stdout, process.stderr].forEach(stream => {
// eslint-disable-next-line
if (stream._handle && typeof stream._handle.setBlocking === 'function') { stream._handle.setBlocking(true); }
});
cmd
.version(pkg.version)
.usage(`[options]${' OR'.em} star code1,code2,code3...,codeN`)
.description('Star is a command line tool for STock Analysis and Research.')
.option('-a, --all' , 'display all stocks.')
.option('-o, --hold' , 'display all held stocks.')
.option('-M, --margin' , 'display stocks that support Margin.')
.option('-C, --cal' , 'display finance calendar of the future month.')
.option('-I, --ignore' , 'display all ignored stocks.')
.option('-i, --insider [c]' , 'display insider trading records of specified stocks. data source: sse or szse')
.option(' --code [code]' , 'specify the stock code of insider tradings you want to query. data source: uzfin.com')
.option(' --market <mkt>' , (`specify the market of insider trading query, case insensitive:SZM-深圳主板, SZGEM-深圳创业板, SZSME-深圳中小板,
SHM-上海主板. multiple market should be separated by "," or ",". `))
.option(' --top-buy' , 'query top buy of insider tradings, should be used with "-i" or "--insider". time span:1m~12m.')
.option(' --top-sell' , 'query top sell of insider tradings, should be used with "-i" or "--insider". time span:1m~12m.')
.option(' --latest-sz' , 'query latest insider tradings of ShenZhen market, should be used with "-i" or "--insider". data source: szse')
.option(' --latest-sh' , 'query latest insider tradings of ShangHai market, should be used with "-i" or "--insider". data source: sse')
.option(' --show-detail' , 'show detail latest insider trading records, should be used with "-i" or "--insider".')
.option('-w, --watch [c1...]', 'watch specified stocks or watch all the stocks in watch list.')
.option('-r, --reverse' , 'sort stocks in ascending order according to designated field.')
.option('-l, --limit <n>' , 'set total display limit of current page.', parseInt)
.option('-p, --page <n>' , 'specify the page index to display.', parseInt)
.option('-d, --data <data>' , 'specify data provider, should be one of "sina" or "tencent".')
.option('-f, --file <file>' , 'specify the symbol file path.')
.option('--from <2014/06/01>', 'specify the beginning date of insider tradings.')
.option('--to <2015/07/09>' , 'specify the ending date of insider tradings.')
.option('--span <3m>' , 'specify the month span of insider tradings ahead of today, should be 1m~24m.')
.option('-L, --lte <pct> ' , 'filter the symbols whose upside potential is lower than or equal to the specified percentage.', parseInt)
.option('-G, --gte <pct> ' , 'filter the symbols whose upside potential is greater than or equal to the specified percentage.', parseInt)
.option('-U, --under <star>' , 'filter the symbols whose star is under or equal to the specified star value.', parseInt)
.option('-A, --above <star>' , 'filter the symbols whose star is above or equal to the specified star value.', parseInt)
.option('--lteb [pct]' , "filter the symbols whose current price is lower than or equal to it's buy/cheap price", parseInt)
.option('--gtes [pct]' , "filter the symbols whose current price is greater than or equal to it's sell/expensive price", parseInt)
.option('-g, --grep <kw> ' , 'specify the keyword to grep in name or comment, multiple keywords should be separated by ",".')
.option('--remove <kw> ' , (`remove the symbols from result with the specified keywords in name or comment, multiple keywords
should be separated by ",".`))
.option('-e, --exclude <pre>', (`exclude stocks whose code number begin with: 300,600,002 or 000, etc. multiple prefixs can be
used and should be separated by "," or ",". `))
.option('-c, --contain <pre>', `display stocks whose code number begin with: 300,600,002 or 000, etc. multiple prefixs can be
used and should be separated by "," or ",". `)
.option('-s, --sort <sort>' , (`specify sorting field, could be sorted by: code/star/price/targetp/incp/bdiff/sdiff/capacity/
pe/pb to sort stocks by code, star, price, price to target percent, price increase percent,
(s.price - s.cheap)/s.price, (s.price - s.expensive)/s.price, capacity, PE and PB separately.
and sort by capacity/pe/pb only works while using tencent data source.`))
.parse(process.argv);
let actions = {
WATCH: function watch(){
let Watch = require('./lib/watch').Watch;
Watch.doWatch(cmd.watch);
},
CAL: function cal(){
let Cal = require('./lib/cal').Cal;
Cal.showCal();
},
INSIDER: function insider(){
let async = require('async');
let Insider = require('./lib/insider').Insider;
if(cmd.latestSz){ Insider.querySZLatest(); return false; }
if(cmd.latestSh){ Insider.querySHLatest(); return false; }
if(cmd.topBuy) { Insider.queryTopList('BV'); return false; }
if(cmd.topSell) { Insider.queryTopList('SV'); return false; }
if(cmd.insider === true){ Insider.queryMiscInsider(); return false; }
let query = cmd.insider.replace(/,/g, ',');
let symbols = _.trimEnd(query, ',').split(',');
if(symbols.length > conf.chunkSize){
console.error((`You can query at most ${conf.chunkSize} symbols once.`).error);
return false;
}
async.eachSeries(symbols, (c, callback) => {
Insider.queryInsider(c, callback);
}, () => {
console.log('ALL DONE!');
});
return false;
},
QUERY: function query(){
let Query = require('./lib/query').Query;
Query.doQuery(cmd.args[0]);
},
TRACE: function trace(){
let Trace = require('./lib/trace').Trace;
let symbols = Trace.getFilteredSymbols();
if(!symbols){ return false; }
let symList = _.chunk(symbols, conf.chunkSize);
Promise
.resolve(symList)
.each(syms => Trace.querySymbols(syms))
.then(() => Trace.printResults())
.then(() => Trace.printSummary());
return false;
},
};
let doCmd = function doCmd() {
// 'TRACE' is the default action
action = 'TRACE';
if(cmd.watch) { action = 'WATCH'; }
if(cmd.insider){ action = 'INSIDER'; }
if(cmd.cal) { action = 'CAL'; }
if(cmd.args.length === 1 ){
action = 'QUERY';
} else if (cmd.args.length > 1) {
console.error('Input error, please try again, or run "star -h" for more help.'.error);
return false;
}
actions[action]();
return false;
};
// Get the Job Done!
doCmd();