Dans l'article précédent, nous avons expliqué les stratégies de simplification de la quantification de 30 lignes de code, et dans cet article, nous allons guider les débutants de la quantification de plus en plus près de l'amusement de la conception de stratégies de quantification. L'auteur, qui est encore un ignorant de la finance, de l'investissement, des valeurs mobilières et autres, continue: "Je ne comprends même pas le processus de négociation des contrats à terme. Il y a des gens qui ont l'impression d'être dans un état d'inconscient, de perplexité, de perplexité à cause des noms et des termes qu'ils n'ont pas encore entendus, mais qui ont l'impression d'être dans un état d'inconscient (ce qui est aussi un peu compréhensif! Après avoir consulté le contenu, j'ai eu les concepts de base à l'esprit, et j'ai combiné mon langage JS que je connaissais un peu, pour écrire une simple lettre. En termes simples, la ligne K est un indicateur de la tendance du marché dans un certain cycle, qui permet d'observer la dynamique du marché. La ligne moyenne est l'indicateur utilisé dans l'article précédent et, comme l'indicateur MACD, reflète la tendance du marché. Les concepts, les algorithmes, les formules d'induction, etc. de ces deux indicateurs ne sont pas décrits de la même manière.
Nom de la variable | Valeur initiale | Expliquer |
---|---|---|
L'intervalle | 2000 | Cette variable est le cycle de consultation, c'est-à-dire la durée pendant laquelle le programme est en attente de suspension. L'unité est une milliseconde, 1000 millisecondes est une seconde, donc cette variable a une valeur initiale de 2 secondes. |
Réservé à l'État | 0 | C'est une variable d'affichage de l'état, qui indique un espace libre. |
Résultats de l'enquête | 1 | C'est une variable d'état qui indique que vous avez plusieurs positions. |
Résultats de l'analyse | 2 | La variable d'état indique une position en libre-échange. |
Résultats de l'analyse | 3 | La variable d'état de détention indique qu'elle n'est pas en stock. |
Nom de l'équipe | 4 | Il y a des centaines de milliers d'entre eux. |
État | Réservé à l'État | Variable d'état, initialement en état d'impasse. |
SignalDelay (décalage du signal) | 0 | Le signal a été retardé et n'est pas utile pour le moment. |
ArrêtezProfit | 0.002 | Cette variable est plus importante, le taux de stop-loss, par exemple, le capital * taux de stop-loss ((0.002)) indique un maximum de perte de 0,002 fois le capital, la perte maximale. |
étape | 0.5 | La longueur de pas de l'arrêt de glissement. |
Op Montant | 1 | Le nombre d'opérations est fixe. |
bénéfice | 0 | Je suis désolée. |
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){//初始 止损价为0 时
this.stopPrice = this.price * ( 1 - stopProfit );
}
if( ticker.Last <= this.price ){ //最后成交价 小于等于 持仓均价时
this.stopPrice = this.price * ( 1 - stopProfit );
this.level = 1;
}else{//其它情况
if( ticker.Last - this.price > 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 MACD_Cross(){//检测MACD指标,交叉状态的函数
var records = exchange.GetRecords();//获取K线数据
while(!records || records.length < 45){ //K线数据不能为null,要大于45个柱,不符合标准 循环获取直到符合
records = exchange.GetRecords();
Sleep(Interval);
}
var macd = TA.MACD(records,12,26,9);//调用指标函数, 参数为MACD 默认的参数。
var dif = macd[0]; //dif线
var dea = macd[1]; //dea线
var column = macd[2]; // MACD柱
var len = records.length; //K线周期长度
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.2 ){
//判断金叉条件:dif 与 dea 此刻均大于0 , 且dif由下上穿dea , 且 MACD量柱大于0.2
return 1; //返回1 代表 金叉信号。
}
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.2 ){
//判断死叉条件:
return 2;//返回2 代表 死叉信号。
}
return 0; //金叉 、死叉 信号以外,为等待信号 0 。
}
function getTimeByNormal(time){// 获取时间的 函数 把毫秒时间 转换 标准时间
var timeByNormal = new Date();
timeByNormal.setTime(time);
var strTime = timeByNormal.toString();
var showTimeArr = strTime.split(" ");
var showTime = showTimeArr[3]+"-"+showTimeArr[1]+"-"+showTimeArr[2]+"-"+showTimeArr[4];
return showTime;
}
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();//在while循环内 获取 市场行情
if(!ticker){//如果 没有获取到 (null) 跳过以下 重新循环
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);//轮询
}
}
function scan(){
var sellInfo = null; //声明 储存平仓信息的变量 , 初始化null
var buyInfo = null; //声明 开仓的 , 初始化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 ){
//判断策略运行状态是否空闲、此刻MACD指标信号是否空闲, 符合 策略运行状态空闲 且 有金叉或死叉执行以下
holdOrder.initHoldOrder();//初始化持仓信息
opFun = singal === 1 ? $.Buy : $.Sell ;//根据MACD_Cross函数返回结果,判断开多仓、开空仓。
buyInfo = opFun(opAmount);//开仓操作
holdOrder.orderState = ORDER_VALID;//设置持仓信息,状态为持仓
holdOrder.price = buyInfo.price; //设置持仓均价 由 开仓操作函数 opFun返回。
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;// 把持仓均价 赋值 给 lastPrice
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 ){//做多时,MACD指标死叉 -- 死叉平仓
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 ){//做空时,MACD指标金叉 ---金叉平仓
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);//轮询间隔,就是让程序暂停一会儿。
}
}
Je vais vous parler des principes de l'arrêt du glissement.
Dans ce code sur l'arrêt du glissement, il est indiqué qu'il y a une différence entre les deux.SetStopPrice
Les fonctions sont basées sur les données transmisesstopState
(arrêt) etticker
(données du marché) pour mettre à jour le prix de stop-loss.stopState === STATE_BUY
Le prix de l'offre est calculé sur la base de la valeur de l'offre.orderState
Pour l'état nul (c'est-à-dire pas de position en vigueur), retournez le prix de stop-loss actuel. Si le prix de stop-loss est 0, initializez-le au prix moyen de l'achat multiplié par(1 - stopProfit)
Dans le même temps, le prix final de la transaction est calculé en fonction de l'évolution de la situation.ticker.Last
Le prix de l'acquisition et de la détentionthis.price
La différence entre la valeur de l'écartement et la valeur de l'écartement de la valeur de l'écartement est la valeur de l'écartement de la valeur de l'écartement.this.level
) est comparé au multiplicateur de la longueur d'étape. Si le niveau actuel est dépassé, le prix de stop-loss est mis à jour à la valeur après le glissement, tout en augmentant le niveau de stop-loss. Sinon, le prix de stop-loss actuel est maintenu.stopState === STATE_SELL
La logique est similaire, mais l'écart entre le prix de la transaction finale et le prix de l'acquisition est négatif, et l'écart est diminué lors de la mise à jour du prix de cessation. Enfin, le prix de cessation est retourné après la mise à jour.
Le stop-loss est une stratégie de gestion des risques.
Au cours de la tenue, le prix de stop-loss est ajusté en fonction des fluctuations du prix du marché afin de réduire les pertes ou de protéger les bénéfices. Selon la logique du code, les points clés pour réaliser un stop-loss glissant sont les suivants:updateCurrentProfit
La méthode est utilisée pour mettre à jour les gains et les pertes actuels en fonction de l'état de détention et du dernier prix (lastPrice). Si le détenu est à vendre (STATE_SELL), les gains sont multipliés par la différence entre le prix le plus récent et le prix de détention; si le détenu est à acheter (STATE_BUY), les gains et les pertes sont négatifs. La méthode SetStopPrice est utilisée pour mettre à jour les prix de stop-loss.1 - stopProfit
Si le prix final est supérieur à la longueur d'avance de la position actuelle, le prix de la transaction est placé comme prix de la transaction après le glissement et le niveau de la transaction est élevé. Dans le cas contraire, le prix de la transaction reste le même. Si le niveau de la transaction est nul, la logique est similaire.
Les sources
le milieu du cielBonjour, je suis un échangeur de billets sur www.banbiren.com, auteur d'une plateforme de change, j'apprends à quantifier les transactions, mon QQ: 39866099, pouvez-vous m'inviter à rejoindre le groupe, je ne peux pas me joindre à la recherche?
NulLes progrès sont rapides.
la muieC'était dur.
L'inventeur de la quantification - un petit rêveBon ^^, vous pouvez postuler directement, MAC QQ n'a pas trouvé de place >_<, 1 groupe numéro: 309368835 Il y a maintenant plusieurs places.
L'inventeur de la quantification - un petit rêveJe ne sais pas si c'est une bonne idée.
L'inventeur de la quantification - un petit rêveNous avons étudié ensemble.