|
|
上一篇文章中我们大家领略了?30行代码的精简量化策略,本篇中作者将一步一步带领量化初学者更近一步地去发掘量化策略设计的乐趣。
正文继续,本次依然是用BTC的现货交易讲解,作者之前在金融、投资、证券等方面也完全是小白一枚。甚至都搞不懂期货的交易流程,
更是被眼花缭乱、听所未闻的名词、术语搞的头昏脑涨,(其实现在也是略懂!略懂!)。通过自己百度、查资料等一一补脑。
查阅了相关内容,心中有了基本的概念,结合自己略懂的JS语言,简单写了一个。最初不懂什么是K线、均线、MACD指标。
在这里简单说下,K线是记录一定周期内的市场行情,便于观察市场动态。均线是上一篇文章用到的指标,和MACD指标一样,都是反映市场行情趋势的指标。
这2种指标的概念、算法、公式推导等就不一一赘述了。不明白的请查百度。(我就是在百度看的!)
代码中有以下全局变量,老规矩,先一一解释,老鸟可忽略。[td]| 变量名 | 初始值 | 说明 | | Interval | 2000 | 这个变量是轮询周期,就是程序暂停等待的时间量,单位是毫秒,1000毫秒为1秒,所以这个变量初始值为2秒。 | | STATE_FREE | 0 | 这个是一个表示状态的变量,表示空闲。用于状态判断。 | | STATE_BUY | 1 | 这个是一个表示状态的变量,表示多头持仓。 就是 买开仓。 | | STATE_SELL | 2 | 状态变量,表示空头持仓。 就是卖开仓。 | | ORDER_INVALID | 3 | 持仓状态变量,表示未持仓。 | | ORDER_VALID | 4 | 表示持仓中… | | state | STATE_FREE | 状态变量,用空闲状态初始化。 | | SignalDelay | 0 | 最初计划 信号延迟,暂时无用。 | | stopProfit | 0.002 | 这个变量比较重要,止损率, 比如 本金 * 止损率(0.002) 表示 最多赔 本金的0.002倍,损失上限。 | | step | 0.5 | 滑动止损的步长值。用于提升、下调 止损价的等级。 | | opAmount | 1 | 固定的操作量。 | | profit | 0 | 盈亏。 |
- //经验1、 对象赋值 当对象 含有 成员函数时 以下赋值会有问题
- /*
- holdOrder = {
- orderState: ORDER_VALID,
- price: buyInfo.price,
- amount: buyInfo.amount,
- time: getTimeByNormal((new Date()).getTime()),
- };
- //应当这样赋值:
- holdOrder.orderState = ORDER_VALID;
- holdOrder.price = buyInfo.price;
- holdOrder.amount = buyInfo.amount;
- holdOrder.time = getTimeByNormal((new Date()).getTime());
- */
- function MACD_Cross(){
- var records = exchange.GetRecords();
- while(!records || records.length < 45){
- records = exchange.GetRecords();
- Sleep(Interval);
- }
- var macd = TA.MACD(records,12,26,9);
- var dif = macd[0];
- var dea = macd[1];
- var column = macd[2];
- var len = records.length;
- if( (dif[len-1] > 0 && dea[len-1] > 0) && dif[len-1] > dea[len-1] && dif[len-2] < dea[len-2] && column[len-1] > 0.08 ){
- return 1;
- }
- if( (dif[len-1] < 0 && dea[len-1] < 0) && dif[len-1] < dea[len-1] && dif[len-2] > dea[len-2] ){
- return 2;
- }
- return 0;
- }
- var Interval = 500;
- var STATE_FREE = 0;
- var STATE_BUY = 1;
- var STATE_SELL = 2;
- var ORDER_INVALID = 3;
- var ORDER_VALID = 4;
- var state = STATE_FREE;
- var SignalDelay = 0;
- var stopProfit = 0.002;
- var step = 0.5;
- var opAmount = 1;
- var profit = 0;
- var holdOrder = {
- orderState: ORDER_INVALID,
- price: 0,
- amount: 0,
- time: null,
- stopPrice: 0,
- level: 1,
- updateCurrentProfit: function(lastPrice,amount){
- if(state === STATE_SELL){
- return (lastPrice - this.price) * amount;
- }
- if(state === STATE_BUY){
- return - (lastPrice - this.price) * amount;
- }
- },
- SetStopPrice: function(ticker,stopState){
- if(stopState === STATE_FREE){
- return this.stopPrice;
- }
- if(stopState === STATE_BUY){
- if(this.orderState === ORDER_INVALID){
- return this.stopPrice;
- }
- if(this.stopPrice === 0){
- this.stopPrice = this.price * ( 1 - stopProfit );
- }
- if( ticker.Last this.level * step ){
- this.stopPrice = this.price * (1 - stopProfit) + (ticker.Last - this.price );
- this.level++;
- }else{
- this.stopPrice = this.stopPrice;
- }
- }
- }else if( stopState === STATE_SELL){
- if(this.orderState === ORDER_INVALID){
- return this.stopPrice;
- }
- if(this.stopPrice === 0){
- this.stopPrice = this.price * ( 1 + stopProfit );
- }
- if( ticker.Last >= this.price ){
- this.stopPrice = this.price * ( 1 + stopProfit );
- this.level = 1;
- }else{
- if( this.price - ticker.Last > this.level * step ){
- this.stopPrice = this.price * (1 + stopProfit) - ( this.price - ticker.Last );
- this.level++;
- }else{
- this.stopPrice = this.stopPrice;
- }
- }
- }
- return this.stopPrice;
- },
- initHoldOrder: function(){
- this.orderState = ORDER_INVALID;
- this.price = 0;
- this.amount = 0;
- this.time = null;
- this.stopPrice = 0;
- this.level = 1;
- }
- };
- function scan(){
- var sellInfo = null;
- var buyInfo = null;
- var opFun = null;
- var singal = 0;
- while(true){
- var ticker = exchange.GetTicker();
- if(!ticker){
- continue;
- }
- holdOrder.SetStopPrice(ticker,state);
- if(state === STATE_FREE && (singal = MACD_Cross()) !== 0 ){
- holdOrder.initHoldOrder();
- opFun = singal === 1 ? $.Buy : $.Sell ;
- buyInfo = opFun(opAmount);
- holdOrder.orderState = ORDER_VALID;
- holdOrder.price = buyInfo.price;
- holdOrder.amount = buyInfo.amount;
- holdOrder.time = $.getTimeByNormal((new Date()).getTime());
- state = singal === 1 ? STATE_BUY : STATE_SELL;
- var account = $.GetAccount(exchange);
- if(singal === 1){
- Log("开多仓。","账户:",account);
- }else{
- Log("开空仓。","账户:",account);
- }
- break;
- }else{
- var lastPrice = holdOrder.price;
- if( state === STATE_BUY && holdOrder.orderState === ORDER_VALID && ticker.Last < holdOrder.stopPrice ){
- Log("多头止损平仓","初始止损价:",holdOrder.price * (1 - stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
- sellInfo = $.Sell(holdOrder.amount);
- holdOrder.orderState = ORDER_INVALID;
- holdOrder.price = sellInfo.price;
- holdOrder.amount = sellInfo.amount;
- holdOrder.time = $.getTimeByNormal((new Date()).getTime());
- profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
- state = STATE_FREE;
- break;
- }
- if( state === STATE_SELL && holdOrder.orderState === ORDER_VALID && ticker.Last > holdOrder.stopPrice ){
- Log("空头止损平仓","初始止损价:",holdOrder.price * (1 + stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
- sellInfo = $.Buy(holdOrder.amount);
- holdOrder.orderState = ORDER_INVALID;
- holdOrder.price = sellInfo.price;
- holdOrder.amount = sellInfo.amount;
- holdOrder.time = $.getTimeByNormal((new Date()).getTime());
- profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
- state = STATE_FREE;
- break;
- }
- if(state === STATE_BUY && MACD_Cross() === 2 ){
- sellInfo = $.Sell(holdOrder.amount);
- Log("死叉平仓","初始止损价:",holdOrder.price * (1 - stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
- holdOrder.orderState = ORDER_INVALID;
- holdOrder.price = sellInfo.price;
- holdOrder.amount = sellInfo.amount;
- holdOrder.time = $.getTimeByNormal((new Date()).getTime());
- profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
- state = STATE_FREE;
- break;
- }
- if(state === STATE_SELL && MACD_Cross() === 1 ){
- sellInfo = $.Buy(holdOrder.amount);
- Log("金叉平仓","初始止损价:",holdOrder.price * (1 + stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
- holdOrder.orderState = ORDER_INVALID;
- holdOrder.price = sellInfo.price;
- holdOrder.amount = sellInfo.amount;
- holdOrder.time = $.getTimeByNormal((new Date()).getTime());
- profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
- state = STATE_FREE;
- break;
- }
- }
- Sleep(Interval);
- }
- }
- function main(){
- var initAccount = $.GetAccount(exchange);
- var nowAccount = initAccount;
- var diffMoney = 0;
- var diffStocks = 0;
- var repair = 0;
- var ticker = exchange.GetTicker();
- Log("初始账户:",initAccount);
- while(true){
- scan();
- ticker = exchange.GetTicker();
- if(!ticker){
- continue;
- }
- if(holdOrder.orderState == ORDER_VALID){
- Log("当前持仓:",holdOrder);
- }
- if(holdOrder.orderState == ORDER_INVALID){
- nowAccount = $.GetAccount(exchange);
- diffMoney = nowAccount.Balance - initAccount.Balance;
- diffStocks = nowAccount.Stocks - initAccount.Stocks;
- repair = diffStocks * ticker.Last;
- LogProfit(diffMoney + repair ,"RMB","现在账户:",nowAccount,"本次盈亏:",profit);
- }
- Sleep(Interval);
- }}
复制代码
代码看累了,喝口水歇歇~流程图直观些~上图!先说说关于滑动止损的原理。图片右边,再大致看下 程序执行流程。
大家可以先跑跑回测实验一下,记得要引用“数字货币交易类库”这个模板!另外写的简陋欢迎指正、修改。
代码纯属学习、交流使用,实盘慎用!
参考资料
- 策略源码
- github上的代码库BotVS的代码广场
|
|