autocoin2
Programme de trading automatique FX de BitCoin. En utilisant l'API de Bitflyer, nous avons automatisé le trading de devises virtuelles avec node.js. Comme ce serait merveilleux si l'argent pouvait être augmenté librement pendant le sommeil, dans les toilettes et 24 heures sur 24. .. : gemme: Je veux m'amuser et gagner de l'argent automatiquement! J'ai essayé de réussir avec une si mauvaise motivation humaine.
** Du coup, la conclusion est ... malheureusement pas rentable: cri: Au contraire, il diminue. .. ** **
Cependant, si vous le réglez, vous pouvez faire un profit. (* Nous ne sommes responsables d'aucun dommage. *) Veuillez le faire à vos risques et périls!
** Code publié sur Github **
.
├── autocoin
│ ├── algo.js
│ ├── app.js
│ ├── config.js
│ ├── crypto.js
│ ├── line.js
│ ├── mongo.js
│ └── utils.js
├── container_data
├── homebridge_AWS
│ ├── startAWS.sh
│ └── stopAWS.sh
├── .env
├── Dockerfile
└── docker-compose.yml
Le point d'entrée de ce programme. L'achat et la vente sont répétés en tournant le code dans un processus en boucle.
'use strict';
const config = require('./config');
const moment = require('moment');
const ccxt = require('ccxt');
const bitflyer = new ccxt.bitflyer(config);
const Crypto = require('./crypto')
const Mongo = require('./mongo');
const mongo = new Mongo();
const Line = require('./line');
const line = new Line(config.line_token)
const utils = require('./utils');
const Algo = require('./algo');
//Intervalle de négociation(Secondes)
const tradeInterval = 180;
//Volume de transaction
const orderSize = 0.01;
//jours d'échange
const swapDays = 3;
//Seuil de différence de prix pour la notification
const infoThreshold = 100;
//Paramètres PsychAlgo;Nombre de lignes positif
const psychoParam = {
'range': 10,
'ratio': 0.7,
};
//Valeur du paramètre crossAlgo:Largeur moyenne mobile
const crossParam = {
'shortMA': 5,
'longMA': 30,
};
//Valeur de réglage de la bande de Bollinger
const BBOrder = {
//ordre
'period': 10,
'sigma': 1.7
};
const BBProfit = {
//Rentabilité
'period': 10,
'sigma': 1
};
const BBLossCut = {
//Coupe de perte:Jugement au quotidien
'period': 10,
'sigma': 2.5
};
//Pondération d'algorithme:Définir inutilisé sur 0
const algoWeight = {
// 'psychoAlgo': 0,
// 'crossAlgo': 0,
// 'bollingerAlgo': 1,
'psychoAlgo': 0.1,
'crossAlgo': 0.2,
'bollingerAlgo': 0.7,
};
//Seuil de décision de transaction
const algoThreshold = 0.3;
//Seuil de coupure de perte
const lossCutThreshold = 0.5;
(async function () {
let sumProfit = 0;
let beforeProfit = null;
const nowTime = moment();
const collateral = await bitflyer.fetch2('getcollateral', 'private', 'GET');
//(Minutes)Création d'enregistrement
const crypto = new Crypto();
const beforeHour = crossParam.longMA * tradeInterval;
const timeStamp = nowTime.unix() - beforeHour;
let records = await crypto.getOhlc(tradeInterval, timeStamp);
const algo = new Algo(records);
//Notifier la ligne du démarrage automatique du trading
const strTime = nowTime.format('YYYY/MM/DD HH:mm:ss');
const message = `\n Démarrage automatique du trading\n date: ${strTime}\n collateral: ${collateral.collateral}`;
line.notify(message);
while (true) {
let flag = null;
let label = "";
let tradeLog = null;
const nowTime = moment();
const strTime = nowTime.format('YYYY/MM/DD HH:mm:ss');
//Vérifiez l'état de fonctionnement de l'échange
let health = await bitflyer.fetch2('getboardstate');
if (health.state !== 'RUNNING') {
//Si anormal, au début
console.log('État de fonctionnement de l'échange:', health);
await utils.sleep(tradeInterval * 1000);
continue;
}
//Obtenez le prix actuel
const ticker = await bitflyer.fetchTicker('FX_BTC_JPY');
const nowPrice = ticker.close;
//Mettre à jour l'enregistrement
algo.records.push(nowPrice);
algo.records.shift()
//Initialiser le paramètre pour l'algorithme
let bbRes = null;
let totalEva = 0;
algo.initEva();
//Algorithme commun
let crossRes = algo.crossAlgo(crossParam.shortMA, crossParam.longMA);
let psychoRes = algo.psychoAlgo(psychoParam.range, psychoParam.ratio)
//Examiner l'intérêt ouvert
const jsonOpenI = await bitflyer.fetch2('getpositions', 'private', 'GET', {product_code: "FX_BTC_JPY"});
const openI = utils.chkOpenI(jsonOpenI)
//Affichage commun
console.log('================');
console.log('time:', strTime);
console.log('nowPrice: ', nowPrice);
//S'il y a un intérêt ouvert
if (openI.side) {
//Affichage commun de l'intérêt ouvert
console.log('');
console.log('Contenu d'intérêt ouvert');
console.log(openI);
let diffDays = nowTime.diff(openI.open_date, 'days');
//Si les jours d'échange sont dépassés
if (diffDays >= swapDays) {
//Renvoie l'intérêt ouvert à 0
label = 'Réinitialiser l'intérêt ouvert car les jours d'échange ont été dépassés'
if (openI.side === 'BUY') {
await bitflyer.createMarketSellOrder('FX_BTC_JPY', openI.size);
flag = 'SELL';
} else {
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', openI.size);
flag = 'BUY';
}
sumProfit += openI.pnl;
} else {
//Si le nombre de jours n'est pas dépassé
//Si vous faites un profit
if (openI.pnl > 0) {
label = 'Rentabilité'
bbRes = algo.bollingerAlgo(BBProfit.period, BBProfit.sigma, openI.price);
totalEva = algo.tradeAlgo(algoWeight)
//Il y a un signal à la baisse sur l'intérêt ouvert
if (openI.side === 'BUY' && totalEva < -algoThreshold) {
await bitflyer.createMarketSellOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'SELL';
//Il y a un signal croissant sur l'intérêt ouvert
} else if (openI.side === 'SELL' && totalEva > algoThreshold) {
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'BUY';
}
} else {
//Si tu perds
label = 'Coupe de perte';
//Jugement d'algorithmes au quotidien
const dayPeriods = 60 * 60 * 24;
const lossTimeStamp = nowTime.unix() - dayPeriods * BBLossCut.period;
let dayRecords = await crypto.getOhlc(dayPeriods, lossTimeStamp);
crossRes = algo.crossAlgo(crossParam.shortMA, crossParam.longMA, dayRecords);
psychoRes = algo.psychoAlgo(psychoParam.range, psychoParam.ratio, dayRecords);
bbRes = algo.bollingerAlgo(BBLossCut.period, BBLossCut.sigma, openI.price, dayRecords);
totalEva = algo.tradeAlgo(algoWeight)
//Même si je perds, il y a des signes qu'une grande tendance est à la baisse avec l'achat
if (openI.side === 'BUY' && totalEva < -lossCutThreshold) {
await bitflyer.createMarketSellOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'SELL';
//Même si je perds, j'ai une vente et c'est une grosse tendance et un signe de hausse
} else if (openI.side === 'SELL' && totalEva > lossCutThreshold) {
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'BUY';
}
}
}
//Si vous réglez l'intérêt ouvert
if (flag) {
tradeLog = {
flag: flag,
label: label,
sumProfit: sumProfit,
profit: openI.pnl,
nowPrice: nowPrice,
openPrice: openI.price,
strTime: strTime,
created_at: nowTime._d,
openI: openI,
bollinger: bbRes,
cross: crossRes,
psycho: psychoRes,
totalEva: totalEva,
};
mongo.insert(tradeLog);
console.log('');
console.log(label);
console.log(tradeLog);
}
//Notification de ligne(Si le seuil est dépassé)
if (beforeProfit !== null) {
const profit = openI.pnl;
const diff = Math.abs(sumProfit + profit - beforeProfit);
if (diff >= infoThreshold) {
const message = `\n date: ${strTime}\n sumProfit: ${sumProfit}\n profit: ${profit}\n collateral: ${collateral.collateral}`;
line.notify(message);
beforeProfit = sumProfit + profit;
}
} else {
//Initialisation d'alerte
beforeProfit = sumProfit;
}
} else {
//Si vous n'avez pas d'intérêt ouvert
//Prise en charge des points d'échange 23:30-0:00 Ne pas commander
const limitDay = moment().hours(23).minutes(30).seconds(0)
if (nowTime.isSameOrAfter(limitDay)) {
console.log(' ');
console.log('Prise en charge des points d'échange_23:30-0:00');
//Aller au début sans accepter les commandes
await utils.sleep(tradeInterval * 1000);
continue;
}
//Utilisez Bollinger pour commander
bbRes = algo.bollingerAlgo(BBOrder.period, BBOrder.sigma);
totalEva = algo.tradeAlgo(algoWeight)
if (totalEva > algoThreshold) {
//Ouvrez une position avec [Acheter]
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', orderSize);
flag = 'BUY';
} else if (totalEva < -algoThreshold) {
//Ouvrez une position avec [Vendre]
await bitflyer.createMarketSellOrder('FX_BTC_JPY', orderSize);
flag = 'SELL';
}
//Si vous obtenez un intérêt ouvert
if (flag) {
label = 'Acquisition d'intérêts ouverts';
tradeLog = {
flag: flag,
label: label,
sumProfit: sumProfit,
nowPrice: nowPrice,
bollinger: bbRes,
cross: crossRes,
psycho: psychoRes,
totalEva: totalEva,
strTime: strTime,
created_at: nowTime._d,
};
mongo.insert(tradeLog);
console.log('');
console.log(label);
console.log(tradeLog);
}
}
console.log('');
console.log('★sumProfit: ', sumProfit);
console.log('');
await utils.sleep(tradeInterval * 1000);
}
})();
--tradeInterval: Intervalle d'échange. Le plus court est de 60 secondes. --orderSize: Nombre de commandes --swapDays: le nombre de jours pendant lesquels vous souhaitez garder un intérêt ouvert. Si vous le dépassez, laissez-le aller. --infoThreshold: plage de quantité de ligne pour la notification. Line annoncera que vous perdrez ou gagnerez plus que le montant fixé. --PsychParam: Paramètres utilisés pour l'algorithme de ligne psychologique. --Période --Rapport --crossParam: Paramètres utilisés pour l'algorithme Golden Cross / Dead Cross.
C'est un flux de traitement approximatif.
Commencez à acheter et à vendre Obtenez les détails de la transaction avant l'exécution du code à partir de cryptowatch à utiliser comme matériau de jugement. Notifier que le "démarrage automatique du trading" a commencé en ligne
Démarrer la boucle de trading Boucle autour de l'intervalle de transaction défini.
--Vérifiez l'état de fonctionnement de l'échange de bitflyer En cas d'anomalie, passez au début de la boucle
Obtenez le prix actuel du bitcoin
Algorithme d'utilisation courante Évaluer les fonctions croisées et les fonctions psychologiques
Obtenez le contenu de la position ouverte (position) que vous détenez.
Si vous détenez un intérêt ouvert, vérifiez le nombre de jours pendant lesquels vous détenez un intérêt ouvert. Si les jours de rétention sont plus longs que le nombre de jours spécifié, abandonnez l'intérêt ouvert (Swap or et pour éviter d'être salé.)
--Lorsque la période de conservation est courte
Si rentable, achetez et vendez en fonction de la position et du jugement de l'algorithme
S'il y a une perte, la perte est coupée par le jugement de l'algorithme avec du matériel quotidien La raison pour laquelle la réduction des pertes est utilisée au quotidien est que l'indice est trop fluide s'il s'agit d'une barre minute, et qu'il est nécessaire de porter un jugement sur une grande tendance. En fait, j'avais l'habitude d'utiliser des jambes minuscules dans le passé, mais il était facile d'accumuler de petites pertes ainsi que de perdre la chance de gagner en étant influencé par des flous assez petits. Il est possible de changer les barres des minutes et des heures, il peut donc être judicieux de les ajuster.
--Si un certain montant de profit ou de perte se produit, vous en serez informé par Line.
--Si vous n'avez pas d'intérêt ouvert
――Si c'est 30 minutes juste avant le changement de date, bouclez sans trading. Pour éviter d'obtenir de l'argent de swap plus tôt après avoir obtenu des intérêts ouverts.
--Si ce n'est pas juste avant la date, la position ouverte est acquise par le jugement de l'algorithme.
Il résume les algorithmes d'achat et de vente.
const gauss = require('gauss');
module.exports = class Algo {
constructor(records) {
this.records = records;
//Points d'évaluation de chaque algorithme
//Signal montant:+Signal bas:-
this.eva = {
'psychoAlgo': 0,
'crossAlgo': 0,
'bollingerAlgo': 0
};
}
psychoAlgo(range, ratio, list = this.records) {
//Juger l'achat et la vente par le ratio de lignes positives
let countHigh = 0
//Comptez le nombre de rayons positifs dans n'importe quelle période
for (let i = range; i > 0; i--) {
const before = list[list.length - i - 1];
const after = list[list.length - i];
if (before <= after) {
countHigh += 1;
}
}
let psychoRatio = 0;
psychoRatio = countHigh / range;
if (psychoRatio >= ratio) {
this.eva['psychoAlgo'] = 1;
} else if (psychoRatio <= 1 - ratio) {
this.eva['psychoAlgo'] = -1;
}
return psychoRatio;
}
crossAlgo(shortMA, longMA, list = this.records) {
//Juger l'achat et la vente à la Golden Dead Cross
//Création de moyenne mobile
const prices = new gauss.Vector(list);
const shortValue = prices.ema(shortMA).pop();
const longValue = prices.ema(longMA).pop();
if (shortValue >= longValue) {
this.eva['crossAlgo'] = 1;
} else if (shortValue < longValue) {
this.eva['crossAlgo'] = -1;
}
return {'shortValue': shortValue, 'longValue': longValue};
}
bollingerAlgo(period, sigma, price = this.records.slice(-1)[0], list = this.records) {
//Bande de Bollinger
const prices = new gauss.Vector(list.slice(-period));
//Utiliser SMA
const sma = prices.sma(period).pop();
const stdev = prices.stdev()
const upper = Math.round(sma + stdev * sigma);
const lower = Math.round(sma - stdev * sigma);
if (price <= lower) {
this.eva['bollingerAlgo'] = 1;
} else if (price >= upper) {
this.eva['bollingerAlgo'] = -1;
}
return {'upper': upper, 'lower': lower}
}
tradeAlgo(weight) {
//Jugement de transaction pondéré et complet
let totalEva = 0
//Multipliez les points d'évaluation par leurs poids respectifs et additionnez-les
for (const [key, value] of Object.entries(this.eva)) {
totalEva += value * weight[key];
}
totalEva = Math.round(totalEva * 100) / 100
return totalEva
}
initEva() {
//Initialiser tous les points d'évaluation
Object.keys(this.eva).forEach(key => {
this.eva[key] = 0;
});
}
}
tradeAlgo()
Une décision de transaction est une décision composée basée sur plusieurs algorithmes. Contient des points d'évaluation pour chaque algorithme. Chaque algorithme donne une note de -1 ou +1 en fonction des données du matériau et des paramètres de réglage. Le nombre positif (+1) est une tendance à la hausse Le nombre négatif (-1) est une tendance à la baisse Multipliez chaque algorithme par les points d'évaluation et leurs poids, puis additionnez-les tous ensemble pour calculer le total des points d'évaluation.
Si la valeur absolue du total des points d'évaluation dépasse le seuil dans app.js, la transaction est exécutée. Le trading en position d'achat ou de vente est déterminé par app.js en fonction de la situation.
Si vous souhaitez ajouter un nouvel algorithme ultérieurement, reportez-vous à la procédure ci-dessous.
--Classe d'Algo --this.eva (en ajoutant le même point d'évaluation que le nom de la méthode) --Ajout d'un algorithme comme méthode
bollingerAlgo()
La bande de Bollinger est un algorithme de jugement qui utilise des moyennes mobiles et des écarts types. En gros, plus la valeur absolue de l'écart-type est élevée, plus la capacité de revenir à la moyenne est forte. Je n'y reviendrai pas en détail, mais cette explication est facile à comprendre. Commentaire sur Manex Securities
Utilise 4 variables.
Extrayez la période que vous souhaitez juger de la liste des mouvements de prix. Ensuite, la valeur supérieure et la valeur inférieure de l'écart type spécifié sont calculées en fonction de la liste extraite. Enfin, si le prix est en dehors des bandes d'écart type supérieur et inférieur calculées, un point d'évaluation est ajouté.
Si le prix est inférieur à la valeur inférieure Son prix est inférieur à la tendance, il est donc facile de commencer à augmenter. Ajouter +1 comme tendance haussière
Lorsque le prix est supérieur à la valeur supérieure Son prix est supérieur à la tendance, il est donc facile de le refuser. Ajouter -1 comme tendance baissière
psychoAlgo()
Jugement d'algorithme utilisant le sentiment des investisseurs. Un algorithme qui prédit les fluctuations de prix en déterminant que si l'achat ou la vente est biaisé en permanence, la tendance se poursuivra, ou l'inverse se produira bientôt, et de nombreux achats et ventes seront effectués. Cette page est facile à comprendre. Commentaire sur Manex Securities
Utilisez 3 variables.
Se limiter à la liste de prix pour la période définie, Découvrez le nombre de prix supérieurs au prix précédent et le ratio du prix total. Comparez en utilisant le ratio jugé comme la valeur du ratio et ajoutez des points d'évaluation en tant que tendance à la hausse et à la baisse.
crossAlgo()
Croix d'or que la ligne moyenne mobile à long terme pénètre la ligne moyenne mobile à court terme de bas en haut. Le contraire est une croix morte. L'or est le signe d'une tendance haussière et la croix morte est le signe d'une tendance baissière.
Utilisez 3 variables.
--Courte période --Long terme --Liste de prix
Comme expliqué ci-dessus, si la moyenne mobile à court terme est supérieure à la moyenne mobile à long terme, un point d'évaluation de +1 est donné comme une tendance à la hausse. Si le contraire est vrai, ajoutez -1 au point d'évaluation en tant que croix morte. Puisque je voulais ajouter plus d'élan de tendance, j'ai utilisé la moyenne mobile exponentielle, qui met l'accent sur les derniers mouvements de prix.
Utilisez l'API cryptowatch pour obtenir OHLC immédiatement après l'exécution du programme. OHLC est synonyme de données ouvertes / élevées / basses / fermées et chandeliers.
Line vous informera chaque fois qu'une transaction commence et qu'un certain montant de profit ou de perte se produit.
Cette page est facile à comprendre sur Line Nnotify. Essayez d'utiliser LINE notify
Enregistrez les transactions de vente avec MongoDB. Étant donné que le contenu de la transaction est une acquisition json à partir de l'API bitflyer et non des données standard, j'ai choisi MongoDB de NoSQL.
Il est géré par le conteneur Docker, mais les données sont conservées dans des volumes. Le premier lancement du conteneur Docker crée un répertoire de volume: container_data.
D'autres fonctions utilitaires sont résumées.
Le programme sur AWS peut être activé / désactivé en un seul clic depuis l'iPhone et l'Apple Watch.
Veuillez consulter ce qui suit pour plus de détails. Homebridge officiel
[Philips_Hue lié à l'API! ~ Make Raspberry Home Kit](https://qiita.com/akinko/items/58c650f99f25fc7e3cb5#%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4%E3%82 % 92homekit% E5% 8C% 96% E3% 81% 99% E3% 82% 8B)
Bien que les détails de la transaction soient enregistrés dans MongoDB, nous vous recommandons d'utiliser l'EDI pour les afficher. Naviguer directement depuis MongoDB est assez pénible en raison du format json. S'il s'agit d'un IDE tel qu'IntelliJ, ce sera agréable et facile à voir. Veuillez vous référer à l'article précédent pour la méthode de paramétrage d'IntelliJ. [Résumé de la méthode de configuration pour faire fonctionner AWS à partir d'IntelliJ](https://qiita.com/akinko/items/d7001a8fe3ac87e1790c#db%E3%81%A8%E3%81%AE%E7%B0%A1%E5%8D% 98% E6% 8E% A5% E7% B6% 9A)
Il faut du temps pour que MongoDB devienne accessible en écriture. Il s'agit de créer container_data pour le répertoire de volume. Démarrez-le pour la première fois avec une marge, et s'il n'est pas écrit après un certain temps, redémarrez Docker. Dans mon cas, cela fonctionne bien à partir de la deuxième fois.
Le container_data du répertoire de volume créé est créé avec les privilèges root. Si vous souhaitez le supprimer, ajoutez sudo. Dans mon expérience par inadvertance, lors de la reconstruction de Docker, j'étais un peu accro à une erreur sans remarquer cette autorisation de répertoire.
Profitez et ne réalisez jamais votre rêve de revenus sans emploi: skull :: skull: C'est persistant, mais ce n'est pas toujours rentable, alors prenez vos propres risques. : point_up_tone3:
Peut-être Mon algorithme, ou le seul paramètre que je n'aime pas, peut être rentable avec un algorithme ajouté par quelqu'un. .. ..
Dans un tel cas, dites-moi en secret: musical_note: Ensuite, si vous le souhaitez, profitez-en comme passe-temps.
Recommended Posts