autocoin2
Das automatische FX-Handelsprogramm von BitCoin.
Mit der Bitflyer-API haben wir den Handel mit virtuellen Währungen mit node.js automatisiert.
Wie schön wäre es, wenn das Geld im Schlaf, auf der Toilette und 24 Stunden am Tag frei erhöht werden könnte. .. : gem:
Ich möchte Spaß haben und automatisch Geld verdienen! Ich habe versucht, es mit einer so schlechten menschlichen Motivation zu schaffen.
** Plötzlich ist die Schlussfolgerung ... leider nicht rentabel: schreien: Vielmehr nimmt es ab. .. ** **.
Wenn Sie es jedoch einstellen, können Sie einen Gewinn erzielen. (* Wir haften nicht für Schäden. *) Bitte tun Sie dies auf eigenes Risiko!
** Code auf Github veröffentlicht **
.
├── 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
Der Einstiegspunkt für dieses Programm. Das Kaufen und Verkaufen wird wiederholt, indem der Code in einem Schleifenprozess gedreht wird.
'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');
//Handelsintervall(Sekunden)
const tradeInterval = 180;
//Transaktionsvolumen
const orderSize = 0.01;
//Tage tauschen
const swapDays = 3;
//Preisdifferenzschwelle für Benachrichtigung
const infoThreshold = 100;
//PsychAlgo-Einstellungen;Positive Zeilenzahl
const psychoParam = {
'range': 10,
'ratio': 0.7,
};
//crossAlgo-Einstellwert:Gleitende Durchschnittsbreite
const crossParam = {
'shortMA': 5,
'longMA': 30,
};
//Bollinger-Band-Einstellwert
const BBOrder = {
//bestellen
'period': 10,
'sigma': 1.7
};
const BBProfit = {
//Rentabilität
'period': 10,
'sigma': 1
};
const BBLossCut = {
//Verlustschnitt:Tägliches Urteil
'period': 10,
'sigma': 2.5
};
//Algorithmusgewichtung:Setzen Sie unbenutzt auf 0
const algoWeight = {
// 'psychoAlgo': 0,
// 'crossAlgo': 0,
// 'bollingerAlgo': 1,
'psychoAlgo': 0.1,
'crossAlgo': 0.2,
'bollingerAlgo': 0.7,
};
//Transaktionsentscheidungsschwelle
const algoThreshold = 0.3;
//Verlustschwelle
const lossCutThreshold = 0.5;
(async function () {
let sumProfit = 0;
let beforeProfit = null;
const nowTime = moment();
const collateral = await bitflyer.fetch2('getcollateral', 'private', 'GET');
//(Protokoll)Datensatzerstellung
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);
//Benachrichtigen Sie Line über den automatischen Handelsstart
const strTime = nowTime.format('YYYY/MM/DD HH:mm:ss');
const message = `\n Automatischer Handelsstart\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');
//Überprüfen Sie den Betriebsstatus der Vermittlungsstelle
let health = await bitflyer.fetch2('getboardstate');
if (health.state !== 'RUNNING') {
//Wenn abnormal, zu Beginn der Zeit
console.log('Betriebsstatus der Vermittlungsstelle:', health);
await utils.sleep(tradeInterval * 1000);
continue;
}
//Aktuellen Preis abrufen
const ticker = await bitflyer.fetchTicker('FX_BTC_JPY');
const nowPrice = ticker.close;
//Datensatz aktualisieren
algo.records.push(nowPrice);
algo.records.shift()
//Initialisieren Sie Param für den Algorithmus
let bbRes = null;
let totalEva = 0;
algo.initEva();
//Gemeinsamer Algorithmus
let crossRes = algo.crossAlgo(crossParam.shortMA, crossParam.longMA);
let psychoRes = algo.psychoAlgo(psychoParam.range, psychoParam.ratio)
//Untersuchen Sie offenes Interesse
const jsonOpenI = await bitflyer.fetch2('getpositions', 'private', 'GET', {product_code: "FX_BTC_JPY"});
const openI = utils.chkOpenI(jsonOpenI)
//Gemeinsame Anzeige
console.log('================');
console.log('time:', strTime);
console.log('nowPrice: ', nowPrice);
//Wenn es offenes Interesse gibt
if (openI.side) {
//Gemeinsame Anzeige von offenem Interesse
console.log('');
console.log('Open-Interest-Inhalte');
console.log(openI);
let diffDays = nowTime.diff(openI.open_date, 'days');
//Wenn die Swap-Tage überschritten werden
if (diffDays >= swapDays) {
//Geben Sie das offene Interesse auf 0 zurück
label = 'Open Interest zurücksetzen, da die Swap-Tage überschritten wurden'
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 {
//Wenn die Anzahl der Tage nicht überschritten wird
//Wenn Sie Gewinn machen
if (openI.pnl > 0) {
label = 'Rentabilität'
bbRes = algo.bollingerAlgo(BBProfit.period, BBProfit.sigma, openI.price);
totalEva = algo.tradeAlgo(algoWeight)
//Es gibt ein Abwärtssignal für das offene Interesse
if (openI.side === 'BUY' && totalEva < -algoThreshold) {
await bitflyer.createMarketSellOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'SELL';
//Es gibt ein steigendes Signal für Open Interest
} else if (openI.side === 'SELL' && totalEva > algoThreshold) {
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'BUY';
}
} else {
//Wenn Sie verlieren
label = 'Verlustschnitt';
//Tägliche Beurteilung des Algorithmus
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)
//Obwohl ich verliere, gibt es Anzeichen dafür, dass ein großer Trend beim Kauf nach unten geht
if (openI.side === 'BUY' && totalEva < -lossCutThreshold) {
await bitflyer.createMarketSellOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'SELL';
//Obwohl ich verliere, habe ich einen Verkauf und es ist ein großer Trend und ein Zeichen des Aufstiegs
} else if (openI.side === 'SELL' && totalEva > lossCutThreshold) {
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', openI.size);
sumProfit += openI.pnl;
flag = 'BUY';
}
}
}
//Wenn Sie das offene Interesse begleichen
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);
}
//Leitungsbenachrichtigung(Wenn der Schwellenwert überschritten wird)
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 {
//Alarminitialisierung
beforeProfit = sumProfit;
}
} else {
//Wenn Sie kein offenes Interesse haben
//Austauschpunktunterstützung 23:30-0:00 Nicht bestellen
const limitDay = moment().hours(23).minutes(30).seconds(0)
if (nowTime.isSameOrAfter(limitDay)) {
console.log(' ');
console.log('Unterstützende Swap-Punkte_23:30-0:00');
//Gehen Sie zum Anfang, ohne Bestellungen anzunehmen
await utils.sleep(tradeInterval * 1000);
continue;
}
//Verwenden Sie Bollinger, um zu bestellen
bbRes = algo.bollingerAlgo(BBOrder.period, BBOrder.sigma);
totalEva = algo.tradeAlgo(algoWeight)
if (totalEva > algoThreshold) {
//Eröffnen Sie eine Position mit [Kaufen]
await bitflyer.createMarketBuyOrder('FX_BTC_JPY', orderSize);
flag = 'BUY';
} else if (totalEva < -algoThreshold) {
//Eröffne eine Position mit [Verkaufen]
await bitflyer.createMarketSellOrder('FX_BTC_JPY', orderSize);
flag = 'SELL';
}
//Wenn Sie offenes Interesse bekommen
if (flag) {
label = 'Open Interest Akquisition';
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: Handelsintervall. Der kürzeste ist 60 Sekunden. --orderSize: Anzahl der Bestellungen --swapDays: Die Anzahl der Tage, die Sie offen halten möchten. Wenn Sie es überschreiten, lassen Sie es los. --infoThreshold: Zeilenbetrag für die Benachrichtigung. Line gibt bekannt, dass Sie mehr als den festgelegten Betrag verlieren oder gewinnen werden. --PsychParam: Parameter, die für den Algorithmus für psychologische Linien verwendet werden. --Zeitraum --Verhältnis --crossParam: Parameter, die für den Golden Cross / Dead Cross-Algorithmus verwendet werden.
Es ist ein grober Verarbeitungsablauf.
--Start Handelsschleife Schleife um das festgelegte Transaktionsintervall.
--Überprüfen Sie den Betriebsstatus des Bitflyer-Austauschs Wenn dies nicht der Fall ist, gehen Sie zum Anfang der Schleife
Holen Sie sich den aktuellen Bitcoin-Preis
Häufig verwendeter Algorithmus Bewerten Sie Kreuzfunktionen und psychologische Funktionen
Erhalten Sie den Inhalt der offenen Position (Position), die Sie halten.
Wenn Sie Open Interest halten, überprüfen Sie die Anzahl der Tage, an denen Sie Open Interest halten. Wenn die Aufbewahrungstage länger als die angegebene Anzahl von Tagen sind, lassen Sie das offene Interesse los (Tauschen Sie Gold aus, um nicht gesalzen zu werden.)
--Wenn die Aufbewahrungsfrist kurz ist
Wenn Sie profitabel sind, kaufen und verkaufen Sie basierend auf der Beurteilung der Position und des Algorithmus
Wenn es einen Verlust gibt, wird der Verlust durch Algorithmusbeurteilung mit täglichem Material verringert Der Grund, warum die Verlustkürzung täglich angewendet wird, ist, dass der Index zu flüssig ist, wenn es sich um einen Minutenbalken handelt, und dass ein großer Trend beurteilt werden muss. Tatsächlich habe ich in der Vergangenheit winzige Beine verwendet, aber es war leicht, kleine Verluste zu akkumulieren und die Gewinnchance zu verlieren, weil ich von ziemlich kleinen Unschärfen beeinflusst wurde. Es ist möglich, die Minuten- und Stundenbalken zu ändern, daher ist es möglicherweise eine gute Idee, sie anzupassen.
Wenn ein bestimmter Gewinn oder Verlust eintritt, werden Sie von Line benachrichtigt.
Wenn Sie kein offenes Interesse haben
Wenn es 30 Minuten vor der Datumsänderung ist, Schleife ohne Handel. Um zu vermeiden, dass Sie nach dem Öffnen von Zinsen frühzeitig Swap-Geld erhalten.
Wenn es nicht kurz vor dem Datum liegt, wird die offene Position durch die Algorithmusbeurteilung erfasst.
Es fasst die Kauf- und Verkaufsalgorithmen zusammen.
const gauss = require('gauss');
module.exports = class Algo {
constructor(records) {
this.records = records;
//Bewertungspunkte jedes Algorithmus
//Steigendes Signal:+Abwärtssignal:-
this.eva = {
'psychoAlgo': 0,
'crossAlgo': 0,
'bollingerAlgo': 0
};
}
psychoAlgo(range, ratio, list = this.records) {
//Beurteilung von Kauf und Verkauf anhand des Verhältnisses positiver Linien
let countHigh = 0
//Zählen Sie die Anzahl der positiven Strahlen in einem beliebigen Zeitraum
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) {
//Kauf und Verkauf am Goldenen Toten Kreuz beurteilen
//Erstellung mit gleitendem Durchschnitt
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) {
//Bollinger Band
const prices = new gauss.Vector(list.slice(-period));
//Verwenden Sie 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) {
//Gewichtete und umfassende Transaktionsbeurteilung
let totalEva = 0
//Multiplizieren Sie die Bewertungspunkte mit ihren jeweiligen Gewichten und addieren Sie sie
for (const [key, value] of Object.entries(this.eva)) {
totalEva += value * weight[key];
}
totalEva = Math.round(totalEva * 100) / 100
return totalEva
}
initEva() {
//Initialisieren Sie alle Bewertungspunkte
Object.keys(this.eva).forEach(key => {
this.eva[key] = 0;
});
}
}
tradeAlgo()
Eine Transaktionsentscheidung ist eine zusammengesetzte Entscheidung, die auf mehreren Algorithmen basiert. Enthält Bewertungspunkte für jeden Algorithmus. Jeder Algorithmus gibt abhängig von den Materialdaten und den Einstellparametern eine Bewertung von entweder -1 oder +1. Positive Zahl (+1) ist ein Aufwärtstrend Negative Zahl (-1) ist Abwärtstrend Multiplizieren Sie jeden Algorithmus mit den Bewertungspunkten und ihren Gewichten und addieren Sie sie schließlich alle, um die Gesamtbewertungspunkte zu berechnen.
Wenn der Absolutwert der gesamten Bewertungspunkte den Schwellenwert in app.js überschreitet, wird die Transaktion ausgeführt. Ob in der Kauf- oder Verkaufsposition gehandelt wird, wird je nach Situation von app.js festgelegt.
Wenn Sie in Zukunft einen neuen Algorithmus hinzufügen möchten, lesen Sie das folgende Verfahren.
--Algo Klasse --this.eva (Hinzufügen des gleichen Bewertungspunkts wie der Methodenname)
Hinzufügen eines Algorithmus als Methode
app.js
Zusätzliche Gewichtung
Fügen Sie eine Methode hinzu, die Sie auswerten möchten (Vielleicht gibt es viele der gleichen gängigen Algorithmen wie crossAlgo () usw.)
bollingerAlgo()
Das Bollinger-Band ist ein Beurteilungsalgorithmus, der gleitende Durchschnitte und Standardabweichungen verwendet. Grob gesagt ist die Fähigkeit, zum Durchschnitt zurückzukehren, umso größer, je größer der Absolutwert der Standardabweichung ist. Ich werde nicht im Detail darauf eingehen, aber diese Erklärung ist leicht zu verstehen. Kommentar zu Manex Securities
Verwendet 4 Variablen.
Extrahieren Sie den Zeitraum, den Sie beurteilen möchten, aus der Preisbewegungsliste. Als nächstes werden der obere Wert und der untere Wert der angegebenen Standardabweichung basierend auf der extrahierten Liste berechnet. Wenn der Preis außerhalb der berechneten oberen und unteren Standardabweichungsbänder liegt, wird schließlich ein Bewertungspunkt hinzugefügt.
Wenn der Preis niedriger als der niedrigere Wert ist Sein Preis ist niedriger als der Trend, so dass es leicht ist, zu steigen. Addiere +1 als Aufwärtstrend
Wenn der Preis höher als der obere Wert ist Sein Preis ist höher als der Trend, so dass es leicht abzulehnen ist. Addiere -1 als Abwärtstrend
psychoAlgo()
Algorithmusbeurteilung unter Verwendung der Anlegerstimmung. Ein Algorithmus, der Preisschwankungen vorhersagt, indem er bestimmt, dass, wenn entweder Kauf oder Verkauf kontinuierlich voreingenommen sind, die Tendenz anhält oder das Gegenteil bald eintritt und viele Käufe und Verkäufe getätigt werden. Diese Seite ist leicht zu verstehen. Kommentar zu Manex Securities
Verwenden Sie 3 Variablen.
Eingrenzen auf die Preisliste für den festgelegten Zeitraum, Finden Sie die Anzahl der Preise heraus, die höher als der vorherige Preis sind, und das Verhältnis zum Gesamtpreis. Vergleichen Sie anhand des Verhältnisses, das als Verhältniswert bewertet wird, und fügen Sie Bewertungspunkte als Auf- und Abwärtstrend hinzu.
crossAlgo()
Goldenes Kreuz, dass die Linie des langfristigen gleitenden Durchschnitts die Linie des kurzfristigen gleitenden Durchschnitts von unten nach oben durchdringt. Das Gegenteil ist totes Kreuz. Golden ist ein Zeichen für einen Aufwärtstrend und Dead Cross ist ein Zeichen für einen Abwärtstrend.
Verwenden Sie 3 Variablen.
Wie oben erläutert, wird ein Bewertungspunkt von +1 als Aufwärtstrend angegeben, wenn der kurzfristige gleitende Durchschnitt höher als der langfristige gleitende Durchschnitt ist. Wenn das Gegenteil der Fall ist, addieren Sie -1 zum Bewertungspunkt als totes Kreuz. Da ich mehr Trenddynamik hinzufügen wollte, habe ich den exponentiellen gleitenden Durchschnitt verwendet, der die neuesten Preisbewegungen hervorhebt.
Verwenden Sie die Cryptowatch-API, um OHLC unmittelbar nach der Programmausführung abzurufen. OHLC steht für Open / High / Low / Close und Candlestick-Daten.
Line benachrichtigt Sie jedes Mal, wenn eine Transaktion beginnt und ein bestimmter Gewinn oder Verlust auftritt.
Diese Seite ist über Line Nnotify leicht zu verstehen. Versuchen Sie, LINE notify zu verwenden
Erfassen Sie Verkaufstransaktionen mit MongoDB. Da der Transaktionsinhalt eine JSON-Erfassung von der Bitflyer-API und keine Standarddaten ist, habe ich MongoDB von NoSQL gewählt.
Es wird vom Docker-Container betrieben, die Daten bleiben jedoch in Volumes erhalten. Beim ersten Start des Docker-Containers wird ein Volume-Verzeichnis erstellt: container_data.
Andere Dienstprogrammfunktionen sind zusammengefasst.
Das Programm auf AWS kann mit einem Fingertipp von iPhone und Apple Watch ein- und ausgeschaltet werden.
Weitere Informationen finden Sie im Folgenden. Offizielle Homebridge
[Philips_Hue mit API verknüpft! ~ Raspberry Home Kit erstellen](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)
Obwohl die Transaktionsdetails in MongoDB gespeichert sind, empfehlen wir, sie mithilfe der IDE anzuzeigen.
Das Surfen direkt aus MongoDB ist aufgrund des JSON-Formats ziemlich schmerzhaft.
Wenn es sich um eine IDE wie IntelliJ handelt, ist sie schön und leicht zu sehen.
Informationen zur Einstellungsmethode von IntelliJ finden Sie im vorherigen Artikel.
[Zusammenfassung der Einstellungsmethode zum Betreiben von AWS über 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)
Es dauert einige Zeit, bis MongoDB beschreibbar ist. Hiermit werden container_data für das Volume-Verzeichnis erstellt. Starten Sie es zum ersten Mal mit einem Rand. Wenn es nach einer Weile nicht mehr geschrieben wird, starten Sie Docker erneut. In meinem Fall funktioniert es ab dem zweiten Mal einwandfrei.
Die container_data des erstellten Volume-Verzeichnisses werden mit Root-Rechten erstellt. Wenn Sie es löschen möchten, fügen Sie sudo hinzu. Nach meiner versehentlichen Erfahrung war ich beim Neuerstellen von Docker ein wenig fehlerabhängig, ohne diese Verzeichnisberechtigung zu bemerken.
Genieße und verwirklichte niemals deinen Traum vom Arbeitsloseneinkommen: Skull :: Skull: Es ist hartnäckig, aber nicht immer rentabel. Gehen Sie also bitte Ihr eigenes Risiko ein. : point_up_tone3:
Möglicherweise Mein Algorithmus oder der einzige Parameter, den ich nicht mag, kann mit einem von jemandem hinzugefügten Algorithmus rentabel sein. .. ..
In einem solchen Fall sag es mir bitte heimlich: music_note: Dann, wenn Sie möchten, genießen Sie es bitte als Hobby.
Recommended Posts