Repository: fintechees/Expert-Advisor-Studio Branch: master Commit: 0b72f0061d6d Files: 143 Total size: 838.4 KB Directory structure: gitextract_dqvm1vq7/ ├── AI/ │ ├── aitrader_12_eurusd.json │ ├── aitrader_12_gbpusd.json │ └── readme.md ├── EA/ │ ├── Arbitrage/ │ │ ├── README.md │ │ ├── fintechee_external_arbitrage.js │ │ ├── guide_for_fintechee_external_arbitrage.txt │ │ └── sample_trading_arbitrage.js │ ├── Built-in/ │ │ ├── README.md │ │ ├── sample_using_rsi.js │ │ └── sample_using_sma.js │ ├── Chaos/ │ │ ├── chaos.js │ │ └── intro.txt │ ├── CopyTrading/ │ │ ├── README.md │ │ ├── copy_trading_for_oanda.js │ │ ├── copy_trading_for_oanda_guide.txt │ │ ├── copy_trading_locally.js │ │ └── copy_trading_locally_guide.txt │ ├── Martingale/ │ │ ├── improved_martingale.js │ │ ├── improved_martingale.txt │ │ └── sample_martingale.js │ ├── NeuralNetwork/ │ │ ├── nn_example.js │ │ ├── sample_run_neuron_model.js │ │ ├── sample_training_neuron_model.js │ │ └── usage.txt │ ├── Oldie/ │ │ ├── README.md │ │ ├── README.txt │ │ └── fixapi_oanda_arbitrage.js │ ├── Plugin-for-Deribit/ │ │ ├── plugin_for_deribit.js │ │ └── usage.txt │ ├── Plugin-for-EOS/ │ │ ├── decentralized_exchange_eos_approve.js │ │ ├── decentralized_exchange_eos_cancel.js │ │ ├── decentralized_exchange_eos_exec.js │ │ ├── decentralized_exchange_eos_propose.js │ │ ├── decentralized_exchange_eos_unapprove.js │ │ ├── payment_gateway_eos.js │ │ ├── payment_gateway_eos_lib_loader.js │ │ ├── payment_gateway_eos_scatter.js │ │ └── usage.txt │ ├── Plugin-for-FXCM/ │ │ └── README.md │ ├── Plugin-for-MQL/ │ │ ├── README.md │ │ ├── mqlea2fintechee.h │ │ ├── mqlindi2fintechee.h │ │ ├── plugin_for_mql.js │ │ ├── runtestcnn.cpp │ │ ├── testcnn.cpp │ │ ├── testverisig.cpp │ │ └── usage.txt │ ├── Plugin-for-Oanda/ │ │ ├── plugin_for_oanda.js │ │ └── usage.txt │ ├── Plugin-for-SNS/ │ │ ├── plugin_for_sns.js │ │ └── usage.txt │ ├── Plugin-for-SNS-with-OpenAI/ │ │ ├── plugin_for_sns_with_openai.js │ │ └── usage.txt │ ├── Plugin-for-Tensorflow/ │ │ ├── import_export_model.js │ │ ├── plugin_to_load_tensorflow.js │ │ ├── sample_running_cnn_model.js │ │ ├── sample_training_cnn_model.js │ │ ├── test_loading_tensorflow.js │ │ ├── test_xor_powered_by_tensorflow.js │ │ └── usage.txt │ ├── Plugin-for-TradingView/ │ │ └── plugin_for_tradingview.js │ ├── Plugin-for-TrailingStop/ │ │ └── plugin_for_trailingstop.js │ ├── Plugin-for-XCoinCH/ │ │ ├── market_maker_bot.js │ │ └── usage.txt │ ├── PriceAction/ │ │ └── price_action.js │ ├── Sample-for-Workflow/ │ │ ├── callee.js │ │ └── caller.js │ ├── Tips/ │ │ ├── about_API_getData.txt │ │ └── how_to_rename.txt │ └── Utility/ │ ├── historical_data_cleaner.js │ ├── historical_data_viewer.js │ └── usage.txt ├── Indicators/ │ ├── Built-in/ │ │ ├── README.md │ │ ├── ac.js │ │ ├── adx.js │ │ ├── alligator.js │ │ ├── ao.js │ │ ├── atr.js │ │ ├── bands.js │ │ ├── bears.js │ │ ├── bidask.js │ │ ├── bulls.js │ │ ├── cci.js │ │ ├── common.js │ │ ├── demarker.js │ │ ├── ema.js │ │ ├── envelopes.js │ │ ├── fractals.js │ │ ├── heikin-ashi.js │ │ ├── ichimoku.js │ │ ├── lwma.js │ │ ├── macd.js │ │ ├── mfi.js │ │ ├── momentum.js │ │ ├── rsi.js │ │ ├── rvi.js │ │ ├── sar.js │ │ ├── sma.js │ │ ├── smma.js │ │ ├── stochastic.js │ │ ├── volume.js │ │ ├── wpr.js │ │ └── zigzag.js │ ├── Oldie/ │ │ ├── README.md │ │ ├── README.txt │ │ ├── fintechee_oanda_loader.js │ │ └── line_segment_sample.js │ ├── Plugin-for-Data-API/ │ │ ├── crypto_loader.js │ │ └── usage.txt │ ├── Plugin-for-Youtube/ │ │ ├── tutorial_videos.js │ │ └── usage.txt │ ├── atr_comparison/ │ │ ├── README.md │ │ ├── atr_comparison.js │ │ ├── atr_comparison_guide.txt │ │ └── atr_exporter.js │ ├── barrage/ │ │ └── barrage.js │ ├── chart_elements/ │ │ ├── README.md │ │ ├── chart_elements.js │ │ ├── chart_elements_intro.txt │ │ ├── toggle_signals_intro.txt │ │ └── toggle_trading_signals.js │ ├── cursor/ │ │ ├── cursor.js │ │ └── usage.txt │ ├── extra_fractals/ │ │ ├── README.md │ │ ├── extra_fractals.js │ │ └── usage.txt │ ├── extra_mfi/ │ │ ├── extra_mfi.js │ │ └── extra_mfi_guide.txt │ ├── extra_sar/ │ │ └── extra_sar.js │ ├── fibonacci_retracements/ │ │ ├── README.md │ │ ├── fibonacci_retracements.js │ │ └── usage.txt │ ├── order_buttons/ │ │ ├── README.md │ │ └── order_buttons.js │ └── unrealized_pl_and_equity_curve/ │ ├── equity_curve.js │ ├── equity_curve_viewer.js │ ├── how_to_use_equity_curve_unrealized_pl.txt │ ├── unrealized_pl.js │ └── unrealized_pl_viewer.js ├── LICENSE ├── README.md ├── screenshot/ │ └── README.md └── simple_manual.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: AI/aitrader_12_eurusd.json ================================================ {"modelTopology":{"class_name":"Sequential","config":{"name":"sequential_20","layers":[{"class_name":"Conv1D","config":{"filters":6,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"kernel_regularizer":null,"kernel_constraint":null,"kernel_size":[20],"strides":[20],"padding":"valid","dilation_rate":[1],"activation":"relu","use_bias":true,"bias_initializer":{"class_name":"Zeros","config":{}},"bias_regularizer":null,"activity_regularizer":null,"bias_constraint":null,"name":"conv1d_Conv1D20","trainable":true,"batch_input_shape":[null,20,1],"dtype":"float32"}},{"class_name":"Flatten","config":{"name":"flatten_Flatten20","trainable":true}},{"class_name":"Dense","config":{"units":2,"activation":"softmax","use_bias":true,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense20","trainable":true}}]},"keras_version":"tfjs-layers 2.0.0","backend":"tensor_flow.js"},"format":"layers-model","generatedBy":"TensorFlow.js tfjs-layers v2.0.0","convertedBy":null,"weightsManifest":[{"paths":["./aitrader_12_eurusd.weights.bin"],"weights":[{"name":"conv1d_Conv1D20/kernel","shape":[20,1,6],"dtype":"float32"},{"name":"conv1d_Conv1D20/bias","shape":[6],"dtype":"float32"},{"name":"dense_Dense20/kernel","shape":[6,2],"dtype":"float32"},{"name":"dense_Dense20/bias","shape":[2],"dtype":"float32"}]}]} ================================================ FILE: AI/aitrader_12_gbpusd.json ================================================ {"modelTopology":{"class_name":"Sequential","config":{"name":"sequential_8","layers":[{"class_name":"Conv1D","config":{"filters":6,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"kernel_regularizer":null,"kernel_constraint":null,"kernel_size":[20],"strides":[20],"padding":"valid","dilation_rate":[1],"activation":"relu","use_bias":true,"bias_initializer":{"class_name":"Zeros","config":{}},"bias_regularizer":null,"activity_regularizer":null,"bias_constraint":null,"name":"conv1d_Conv1D8","trainable":true,"batch_input_shape":[null,20,1],"dtype":"float32"}},{"class_name":"Flatten","config":{"name":"flatten_Flatten8","trainable":true}},{"class_name":"Dense","config":{"units":2,"activation":"softmax","use_bias":true,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense8","trainable":true}}]},"keras_version":"tfjs-layers 2.0.0","backend":"tensor_flow.js"},"format":"layers-model","generatedBy":"TensorFlow.js tfjs-layers v2.0.0","convertedBy":null,"weightsManifest":[{"paths":["./aitrader_12_gbpusd.weights.bin"],"weights":[{"name":"conv1d_Conv1D8/kernel","shape":[20,1,6],"dtype":"float32"},{"name":"conv1d_Conv1D8/bias","shape":[6],"dtype":"float32"},{"name":"dense_Dense8/kernel","shape":[6,2],"dtype":"float32"},{"name":"dense_Dense8/bias","shape":[2],"dtype":"float32"}]}]} ================================================ FILE: AI/readme.md ================================================ AI Trader https://www.fintechee.com/ai-trader/ We will provide some AI models for free. Our models are designed for long-term timeframes, meaning signals are generated less frequently. However, this approach is the least risky and has the potential to deliver a 30-50% annual profit, excluding compound interest. We store backtesting reports in this repo: https://github.com/fintechees/AI-Trader-Backtesting-Report If you are interested in purchasing our paid AI model, please contact us: admin@fintechee.com. Campaign!! We will provide an Expert Advisor (EA) to the individual trader. Please refer to the M2Report.zip(The file is password-protected, the password is fuckcndictator) file for performance details. The individual trader is required to have a FIX API account. We will set up a dedicated platform for this trader, linked to a single account. The monthly fee is $100 USD, which includes cloud service costs. ================================================ FILE: EA/Arbitrage/README.md ================================================ We will add more details to introduce how to use this EA. ================================================ FILE: EA/Arbitrage/fintechee_external_arbitrage.js ================================================ registerEA( "fintechee_external_arbitrage", "A test EA to trade arbitrage based on the price difference between Fintechee and the external trading platform(v1.0)", [{ name: "externalSys", value: "Oanda", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "autoLoad", value: true, required: true, type: PARAMETER_TYPE.BOOLEAN, range: null }, { name: "autoSave", value: true, required: true, type: PARAMETER_TYPE.BOOLEAN, range: null }, { name: "backgroundColor", value: "#dfc29a", required: true, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var externalSys = getEAParameter(context, "externalSys") if (externalSys == "Oanda") { if (typeof window.pluginForOanda == "undefined") { throw new Error("You need to run plugin_for_oanda(you can find it in our Github repo -- Plugin-for-Oanda) first. If you have run the plugin, please be patient with the loading time.") } } else { throw new Error("The specific external trading platform is not supported.") } var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var currTime = new Date().getTime() if (typeof window.arbitrage == "undefined") { window.arbitrage = { autoLoad: getEAParameter(context, "autoLoad"), autoSave: getEAParameter(context, "autoSave"), bgColor: getEAParameter(context, "backgroundColor"), latestDay: new Date().getDay(), latestSaveTime: currTime, quotes: [], statistics: [], loadStatistics: function () { if (typeof localStorage.reservedZone != "undefined") { var reservedZone = JSON.parse(localStorage.reservedZone) if (typeof reservedZone.arbitrageStatistics != "undefined" && typeof reservedZone.arbitrageStatistics.statistics != "undefined") { if (new Date(reservedZone.arbitrageStatistics.latestSaveTime).getDay() < window.latestDay) { for (var i in reservedZone.arbitrageStatistics.statistics) { var statistics = reservedZone.arbitrageStatistics.statistics[i] this.statistics[statistics.symbolName] = { h: [], h2: [], ph: statistics.h, ph2: statistics.h2 } for (var j = 0; j <= 23; j++) { this.statistics[statistics.symbolName].h.push(0) this.statistics[statistics.symbolName].h2.push(0) } } } else { for (var i in reservedZone.arbitrageStatistics.statistics) { var statistics = reservedZone.arbitrageStatistics.statistics[i] this.statistics[statistics.symbolName] = { h: statistics.h, h2: statistics.h2, ph: statistics.ph, ph2: statistics.ph2 } } } } } }, saveStatistics: function () { var reservedZone = {} if (typeof localStorage.reservedZone != "undefined") { reservedZone = JSON.parse(localStorage.reservedZone) } reservedZone.arbitrageStatistics = { latestSaveTime: new Date().getTime(), statistics: [] } for (var i in this.statistics) { reservedZone.arbitrageStatistics.statistics.push({ symbolName: i, h: this.statistics[i].h, h2: this.statistics[i].h2, ph: this.statistics[i].ph, ph2: this.statistics[i].ph2 }) } localStorage.reservedZone = JSON.stringify(reservedZone) }, count: function (symbolName, hour) { this.statistics[symbolName].h[hour]++ }, count2: function (symbolName, hour) { this.statistics[symbolName].h2[hour]++ }, chartLibUrl: "https://cdn.jsdelivr.net/npm/chart.js@2.8.0", bLibLoaded: false, loadChartJsLib: function () { var tags = document.getElementsByTagName("script") for (var i = tags.length - 1; i >= 0; i--) { if (tags[i] && tags[i].getAttribute("src") != null && tags[i].getAttribute("src") == this.chartLibUrl) { this.bLibLoaded = true break } } var that = this if (!this.bLibLoaded) { var script = document.createElement("script") script.id = "chartjs_lib" document.body.appendChild(script) script.onload = function () { that.bLibLoaded = true that.initArbitrageChart() popupMessage("The ChartJS lib has been loaded successfully!") } script.onerror = function () { that.bLibLoaded = false popupErrorMessage("Failed to load the ChartJS lib.") } script.async = true script.src = this.chartLibUrl } else { this.initArbitrageChart() } }, currentChartSymbolName: "EUR/USD", initArbitrageChart: function () { var ctx = document.getElementById("arbitrage_chart").getContext("2d") var statistics = this.statistics[this.currentChartSymbolName] var labels = [] var data = [] var data2 = [] var pdata = [] var pdata2 = [] for (var i = 0; i <= 23; i++) { labels.push(i + "") data.push(statistics.h[i]) data2.push(statistics.h2[i]) pdata.push(statistics.ph[i]) pdata2.push(statistics.ph2[i]) } this.arbitrageChart = new Chart(ctx, { type: "line", data: { labels: labels, datasets: [{ label: this.currentChartSymbolName + "(F-X)", // F stands for Fintechee, X stands for eXternal sys backgroundColor: "rgba(255,255,255,0)", borderColor: "#DB2828", data: data }, { label: this.currentChartSymbolName + "(X-F)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#21BA45", data: data2 }, { label: this.currentChartSymbolName + "(F-X)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#DB2828", borderDash: [2, 3], data: pdata }, { label: this.currentChartSymbolName + "(X-F)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#21BA45", borderDash: [2, 3], data: pdata2 }] }, options: { responsive: true, maintainAspectRatio: false } }) }, updateArbitrageChart: function (symbolName, bAll, hour) { if (bAll) { for (var i = 0; i <= 23; i++) { this.arbitrageChart.data.datasets[0].data[i] = this.statistics[symbolName].h[i] this.arbitrageChart.data.datasets[2].data[i] = this.statistics[symbolName].ph[i] } } else { this.arbitrageChart.data.datasets[0].data[hour] = this.statistics[symbolName].h[hour] } this.arbitrageChart.update() }, updateArbitrageChart2: function (symbolName, bAll, hour) { if (bAll) { for (var i = 0; i <= 23; i++) { this.arbitrageChart.data.datasets[1].data[i] = this.statistics[symbolName].h2[i] this.arbitrageChart.data.datasets[3].data[i] = this.statistics[symbolName].ph2[i] } } else { this.arbitrageChart.data.datasets[1].data[hour] = this.statistics[symbolName].h2[hour] } this.arbitrageChart.update() }, updatePrevArbitrage: function () { for (var i in this.statistics) { this.statistics[i].ph = this.statistics[i].h this.statistics[i].ph2 = this.statistics[i].h2 this.statistics[i].h = [] this.statistics[i].h2 = [] for (var j = 0; j <= 23; j++) { this.statistics[i].h.push(0) this.statistics[i].h2.push(0) } } }, chartIds: [], initDashboard: function () { if (typeof $("#arbitrage_chart_dashboard").html() == "undefined") { var arbitrageChartPanel = '
' + data + '
' } else { return '' + data + '
' } } }, { title: "Ext-Fintechee", render: function (data, type, row) { if (data > 0) { return '' + data + '
' } else { return '' + data + '
' } } }, { title: "External" }, { title: "Op" } ], headerCallback: function (thead, data, start, end, display) { $(thead).css("background-color", that.bgColor) }, rowCallback: function (row, data, index) { $("td", row).css("background-color", that.bgColor) }, ordering: false, searching: false, bPaginate: false, bLengthChange: false, bFilter: false, bInfo: false, scrollY: "50vh", scrollCollapse: true, paging: false, columnDefs: [ {width: "20%", targets: 0, className: "dt-body-center"}, {width: "20%", targets: 1, className: "dt-body-right"}, {width: "20%", targets: 2, className: "dt-body-right"}, {width: "20%", targets: 3, className: "dt-body-right"}, {width: "20%", targets: 4, className: "dt-body-center"}, {width: "20%", targets: [0], className: "dt-head-center"}, {width: "20%", targets: [1], className: "dt-head-center"}, {width: "20%", targets: [2], className: "dt-head-center"}, {width: "20%", targets: [3], className: "dt-head-center"}, {width: "20%", targets: [4], className: "dt-head-center"}, { targets: -1, data: null, defaultContent: '' + '' + '' } ] }) for (var i in this.quotes) { $("#arbitrage_prices").DataTable().row.add([ i, "", "", "", "" ]).draw(false) } $("#arbitrage_prices tbody").on("click", "[id*=btn_check_arbitrage]", function () { if (typeof that.pricesTable != "undefined") { var data = that.pricesTable.row($(this).parents("tr")).data() if (typeof data == "undefined") { data = that.pricesTable.row($(this)).data() } that.currentChartSymbolName = data[0] that.arbitrageChart.data.datasets[0].label = that.currentChartSymbolName + "(F-X)" // F stands for Fintechee, O stands for eXternal sys that.arbitrageChart.data.datasets[1].label = that.currentChartSymbolName + "(X-F)" that.arbitrageChart.data.datasets[2].label = that.currentChartSymbolName + "(F-X)" that.arbitrageChart.data.datasets[3].label = that.currentChartSymbolName + "(X-F)" that.updateArbitrageChart(data[0], true, -1) that.updateArbitrageChart2(data[0], true, -1) } }) $("#btn_load_arbitrage_statistics").on("click", function () { that.loadStatistics() }) $("#btn_save_arbitrage_statistics").on("click", function () { that.saveStatistics() }) } for (var i in this.quotes) { this.statistics[i] = { h: [], h2: [], ph: [], ph2: [] } for (var j = 0; j <= 23; j++) { this.statistics[i].h.push(0) this.statistics[i].h2.push(0) this.statistics[i].ph.push(0) this.statistics[i].ph2.push(0) } } } } } if (externalSys == "Oanda") { window.arbitrage.quotes = window.pluginForOanda.quotes } window.arbitrage.initDashboard() window.arbitrage.loadChartJsLib() if (window.arbitrage.autoLoad) { window.arbitrage.loadStatistics() } for (var i in window.arbitrage.quotes) { getQuotes(context, brokerName, accountId, i.replace("_", "/")) } }, function (context) { // Deinit() embedHtml("", 2) for (var i in window.arbitrage.chartIds) { moveLayout(window.arbitrage.chartIds[i], 2) } if (!window.arbitrage.bLibLoaded) { var script = document.getElementById("chartjs_lib") script.remove() } }, function (context) { // OnTick() var externalSys = getEAParameter(context, "externalSys") if (externalSys == "Oanda") { if (typeof window.pluginForOanda == "undefined") { return } } else { return } var currTime = new Date().getTime() var hour = new Date(currTime).getHours() var day = new Date(currTime).getDay() if (window.arbitrage.autoSave && currTime - window.arbitrage.latestSaveTime > 60000) { window.arbitrage.saveStatistics() window.arbitrage.latestSaveTime = currTime } var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var currentTick = getCurrentTick(context) var symbolName = currentTick.symbolName var askFintechee = currentTick.ask var bidFintechee = currentTick.bid if (window.arbitrage.latestDay != day) { window.arbitrage.updatePrevArbitrage() window.arbitrage.updateArbitrageChart(symbolName, true, -1) window.arbitrage.updateArbitrageChart2(symbolName, true, -1) window.arbitrage.latestDay = day } if (window.arbitrage.quotes[symbolName] == null) return var askExt = window.arbitrage.quotes[symbolName].ask var bidExt = window.arbitrage.quotes[symbolName].bid if (askFintechee != null && bidFintechee != null && askExt != null && bidExt != null) { var table = $('#arbitrage_prices').DataTable() var tb = $('#arbitrage_prices').dataTable() table.columns().eq(0).each(function (index) { if (index == 0) { var column = table.column(index).data() for (var i in column) { if (isNaN(i)) continue var rowId = parseInt(i) if (column[i] == symbolName) { tb.fnUpdate(Math.round((bidExt - askFintechee) * 100000) / 100000, rowId, 1, false, false) tb.fnUpdate(Math.round((bidFintechee - askExt) * 100000) / 100000, rowId, 2, false, false) tb.fnUpdate(Math.round((askExt + bidExt) / 2 * 100000) / 100000, rowId, 3, false, false) break } } } }) if (bidExt > askFintechee) { window.arbitrage.count(symbolName, hour) if (symbolName == window.arbitrage.currentChartSymbolName) { window.arbitrage.updateArbitrageChart(symbolName, false, hour) } // var msg = new Date() + " " + symbolName + " Chance!! Ext Bid: " + bidExt + ", Fintechee Ask: " + askFintechee + ", Difference: " + (bidExt - askFintechee) + "\n" // printMessage(msg) } if (bidFintechee > askExt) { window.arbitrage.count2(symbolName, hour) if (symbolName == window.arbitrage.currentChartSymbolName) { window.arbitrage.updateArbitrageChart2(symbolName, false, hour) } // var msg = new Date() + " " + symbolName + " Chance!! Fintechee Bid: " + bidFintechee + ", Ext Ask: " + askExt + ", Difference: " + (bidFintechee - askExt) + "\n" // printMessage(msg) } } } ) ================================================ FILE: EA/Arbitrage/guide_for_fintechee_external_arbitrage.txt ================================================ To utilize this EA and display the statistics panel regarding the frequencies of arbitrage opportunities, you must first open the “plugin_for_oanda”. Once you have launched the “plugin_for_oanda”, a panel will appear to set up your Oanda account ID and token information. Simply input the necessary information and hit the “Connect” button. If you successfully log in, two popup messages will appear. Following this, proceed to run “fintechee_external_arbitrage”. You can specify Oanda as your external trading platform. The price variance is derived from two streaming quotes: one from Fintechee’s FIX API engine, and the other from the external trading platform. The statistical analysis is based on hourly tallies, with most of the price variation peaks occurring during 12pm-4pm (UTC). If the numerical value appears as green, it denotes that the price variance is positive, and consequently, an arbitrage opportunity has arisen. ================================================ FILE: EA/Arbitrage/sample_trading_arbitrage.js ================================================ registerEA( "sample_trading_arbitrage", "Two accounts signed up on the different servers are required to trade arbitrage. Additionally please make sure that you have signed in to both accounts and logged out from the accounts in investor mode.(v1.04)", [],// parameters function (context) { // Init() var account1 = getAccount(context, 0) var account2 = getAccount(context, 1) var acc1 = { brokerName: getBrokerNameOfAccount(account1), accountId: getAccountIdOfAccount(account1), symbolName: "EUR/USD" } var acc2 = { brokerName: getBrokerNameOfAccount(account2), accountId: getAccountIdOfAccount(account2), symbolName: "EUR/USD" } getQuotes (context, acc1.brokerName, acc1.accountId, acc1.symbolName) getQuotes (context, acc2.brokerName, acc2.accountId, acc2.symbolName) context.acc1 = acc1 context.acc2 = acc2 }, function (context) { // Deinit() }, function (context) { // OnTick() var currTime = new Date().getTime() if (typeof context.currTime == "undefined") { context.currTime = currTime } else if (context.currTime <= currTime - 1000) { context.currTime = currTime } else { return } var acc1 = context.acc1 var acc2 = context.acc2 var ask1 = null var ask2 = null var bid1 = null var bid2 = null try { ask1 = getAsk(context, acc1.brokerName, acc1.accountId, acc1.symbolName) ask2 = getAsk(context, acc2.brokerName, acc2.accountId, acc2.symbolName) bid1 = getBid(context, acc1.brokerName, acc1.accountId, acc1.symbolName) bid2 = getBid(context, acc2.brokerName, acc2.accountId, acc2.symbolName) } catch (e) { // This try-catch is used to bypass the "error throw" when you start the EA too early to call getAsk or getBid(at that time, bid or ask may be not ready yet.) printErrorMessage(e.message) return } var volume = 0.01 if (ask1 < bid2) { var tradeNum = getOpenTradesListLength(context) var acc1TradeId = null var acc2TradeId = null for (var i = tradeNum - 1; i >= 0; i--) { var trade = getOpenTrade(context, i) var brokerName = getBrokerName(trade) var accountId = getAccountId(trade) var tradeId = getTradeId(trade) var orderType = getOrderType(trade) if (brokerName == acc1.brokerName && accountId == acc1.accountId && orderType == ORDER_TYPE.OP_SELL) { acc1TradeId = tradeId } if (brokerName == acc2.brokerName && accountId == acc2.accountId && orderType == ORDER_TYPE.OP_BUY) { acc2TradeId = tradeId } } if (acc1TradeId == null) { sendOrder(acc1.brokerName, acc1.accountId, acc1.symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else { closeTrade(acc1.brokerName, acc1.accountId, acc1TradeId, 0, 0) } if (acc2TradeId == null) { sendOrder(acc2.brokerName, acc2.accountId, acc2.symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else { closeTrade(acc2.brokerName, acc2.accountId, acc2TradeId, 0, 0) } } else if (ask2 < bid1) { var tradeNum = getOpenTradesListLength(context) var acc1TradeId = null var acc2TradeId = null for (var i = tradeNum - 1; i >= 0; i--) { var trade = getOpenTrade(context, i) var brokerName = getBrokerName(trade) var accountId = getAccountId(trade) var tradeId = getTradeId(trade) var orderType = getOrderType(trade) if (brokerName == acc2.brokerName && accountId == acc2.accountId && orderType == ORDER_TYPE.OP_SELL) { acc2TradeId = tradeId } if (brokerName == acc1.brokerName && accountId == acc1.accountId && orderType == ORDER_TYPE.OP_BUY) { acc1TradeId = tradeId } } if (acc2TradeId == null) { sendOrder(acc2.brokerName, acc2.accountId, acc2.symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else { closeTrade(acc2.brokerName, acc2.accountId, acc2TradeId, 0, 0) } if (acc1TradeId == null) { sendOrder(acc1.brokerName, acc1.accountId, acc1.symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else { closeTrade(acc1.brokerName, acc1.accountId, acc1TradeId, 0, 0) } } } ) ================================================ FILE: EA/Built-in/README.md ================================================ The EAs in this folder will be updated automatically when you open the WEB trader. If you customize the EAs in this folder, please rename them to avoid being overwritten. ================================================ FILE: EA/Built-in/sample_using_rsi.js ================================================ registerEA( "sample_using_rsi", "A test EA based on rsi(v1.01)", [{ // parameters name: "period", value: 20, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] }], function (context) { // Init() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" getQuotes (context, brokerName, accountId, symbolName) context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1) var period = getEAParameter(context, "period") context.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "rsi", [{ name: "period", value: period }]) }, function (context) { // Deinit() }, function (context) { // OnTick() var arrTime = getData(context, context.chartHandle, DATA_NAME.TIME) if (typeof context.currTime == "undefined") { context.currTime = arrTime[arrTime.length - 1] } else if (context.currTime != arrTime[arrTime.length - 1]) { context.currTime = arrTime[arrTime.length - 1] } else { return } var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" var arrRsi = getData(context, context.indiHandle, "rsi") var ask = null var bid = null try { ask = getAsk(context, brokerName, accountId, symbolName) bid = getBid(context, brokerName, accountId, symbolName) } catch (e) { // This try-catch is used to bypass the "error throw" when you start the EA too early to call getAsk or getBid(at that time, bid or ask may be not ready yet.) printErrorMessage(e.message) return } var limitPrice = 0.0003 var stopPrice = 0.0003 var volume = 0.01 if (30 < arrRsi[arrRsi.length - 3] && 30 > arrRsi[arrRsi.length - 2]) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUYLIMIT, ask-limitPrice, 0, volume, ask+limitPrice, bid-3*stopPrice, "", 0, 0) } else if (70 > arrRsi[arrRsi.length - 3] && 70 < arrRsi[arrRsi.length - 2]) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELLLIMIT, bid+limitPrice, 0, volume, bid-limitPrice, ask+3*stopPrice, "", 0, 0) } } ) ================================================ FILE: EA/Built-in/sample_using_sma.js ================================================ registerEA( "sample_using_sma", "A test EA based on sma(v1.04)", [{ // parameters name: "period", value: 20, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] }], function (context) { // Init() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" getQuotes (context, brokerName, accountId, symbolName) context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1) var period = getEAParameter(context, "period") context.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "sma", [{ name: "period", value: period }]) }, function (context) { // Deinit() }, function (context) { // OnTick() var arrTime = getData(context, context.chartHandle, DATA_NAME.TIME) if (typeof context.currTime == "undefined") { context.currTime = arrTime[arrTime.length - 1] } else if (context.currTime != arrTime[arrTime.length - 1]) { context.currTime = arrTime[arrTime.length - 1] } else { return } var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" var arrClose = getData(context, context.chartHandle, DATA_NAME.CLOSE) var arrSma = getData(context, context.indiHandle, "sma") var ask = null var bid = null try { ask = getAsk(context, brokerName, accountId, symbolName) bid = getBid(context, brokerName, accountId, symbolName) } catch (e) { // This try-catch is used to bypass the "error throw" when you start the EA too early to call getAsk or getBid(at that time, bid or ask may be not ready yet.) printErrorMessage(e.message) return } var limitPrice = 0.0003 var stopPrice = 0.0003 var volume = 0.01 if (arrClose[arrClose.length - 3] < arrSma[arrSma.length - 3] && arrClose[arrClose.length - 2] > arrSma[arrSma.length - 2]) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUYLIMIT, ask-limitPrice, 0, volume, ask+limitPrice, bid-3*stopPrice, "", 0, 0) } else if (arrClose[arrClose.length - 3] > arrSma[arrSma.length - 3] && arrClose[arrClose.length - 2] < arrSma[arrSma.length - 2]) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELLLIMIT, bid+limitPrice, 0, volume, bid-limitPrice, ask+3*stopPrice, "", 0, 0) } } ) ================================================ FILE: EA/Chaos/chaos.js ================================================ registerEA( "chaos", "An EA based on Chaos theory(v1.0)", [{ name: "symbolName", value: "EUR/USD", required: true, type: "String", range: null, step: null }, { name: "volume", value: 0.01, required: true, type: "Number", range: [0.01, 1.0], step: null }, { name: "timeFrame", value: "H4", required: true, type: "String", range: null, step: null }], function (context) { // Init() // Bill Williams' Chaos Trading Strategy is amazing. // This EA is based on the theory written in his book "Trading Chaos". var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = getEAParameter(context, "symbolName") var timeFrame = getEAParameter(context, "timeFrame") context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, timeFrame) context.fractalsHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, timeFrame, "fractals", []) context.alligatorHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, timeFrame, "alligator", [{ name: "jawsPeriod", value: 13}, {name: "jawsShift", value: 8}, { name: "teethPeriod", value: 8}, {name: "teethShift", value: 5}, { name: "lipsPeriod", value: 5}, {name: "lipsShift", value: 3}, { name: "method", value: "smma"}]) context.aoHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, timeFrame, "ao", []) context.acHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, timeFrame, "ac", []) context.chaos = { fractalsUpIdx: -1, fractalsDownIdx: -1, fractalsUp: 0, fractalsDown: 0, fractalsUpTriggered: false, fractalsDownTriggered: false, getFractalsSignal: function (arrUp, arrDown) { var cursor = arrUp.length - 4 var latestUpIdx = -1 var latestDownIdx = -1 while (cursor >= 0) { if (arrUp[cursor] != 0) { if (latestUpIdx == -1) { latestUpIdx = cursor } if (latestDownIdx != -1) { break } } if (arrDown[cursor] != 0) { if (latestDownIdx == -1) { latestDownIdx = cursor } if (latestUpIdx != -1) { break } } cursor-- } if (latestUpIdx != -1 && latestDownIdx != -1) { if (latestUpIdx != this.fractalsUpIdx) { this.fractalsUpIdx = latestUpIdx this.fractalsUpTriggered = false } if (latestDownIdx != this.fractalsDownIdx) { this.fractalsDownIdx = latestDownIdx this.fractalsDownTriggered = false } this.fractalsUp = arrUp[latestUpIdx] this.fractalsDown = arrDown[latestDownIdx] } }, checkFractalsSignal: function (arrTeeth, currTick) { if (this.fractalsUp > 0) { if (!this.fractalsUpTriggered) { if (currTick > this.fractalsUp && currTick > arrTeeth[arrTeeth.length - 6]) { this.fractalsUpTriggered = true return 1 } } } if (this.fractalsDown > 0) { if (!this.fractalsDownTriggered) { if (currTick < this.fractalsDown && currTick < arrTeeth[arrTeeth.length - 6]) { this.fractalsDownTriggered = true return 0 } } } return -1 }, aoUpIdx1: -1, aoDownIdx1: -1, aoUp1: 0, aoDown1: 0, aoUpTriggered1: false, aoDownTriggered1: false, aoUpIdx2: -1, aoDownIdx2: -1, aoUp2: 0, aoDown2: 0, aoUpTriggered2: false, aoDownTriggered2: false, aoUpIdx3: -1, aoDownIdx3: -1, aoUp3: 0, aoDown3: 0, aoUpTriggered3: false, aoDownTriggered3: false, getAoSignal: function (arrUp, arrDown, arrHigh, arrLow) { var arrLen = arrHigh.length if (arrUp[arrLen - 2] > 0 && arrDown[arrLen - 3] > 0 && (arrUp[arrLen - 4] > arrDown[arrLen - 3] || arrDown[arrLen - 4] > arrDown[arrLen - 3])) { if (arrLen - 2 != this.aoUpIdx1) { this.aoUpIdx1 = arrLen - 2 this.aoDownIdx1 = -1 this.aoUp1 = arrHigh[arrLen - 2] this.aoDown1 = 0 this.aoUpTriggered1 = false this.aoDownTriggered1 = false } } else if (arrDown[arrLen - 2] < 0 && arrUp[arrLen - 3] < 0 && (arrUp[arrLen - 4] < arrUp[arrLen - 3] || arrDown[arrLen - 4] < arrUp[arrLen - 3])) { if (arrLen - 2 != this.aoDownIdx1) { this.aoUpIdx1 = -1 this.aoDownIdx1 = arrLen - 2 this.aoUp1 = 0 this.aoDown1 = arrLow[arrLen - 2] this.aoUpTriggered1 = false this.aoDownTriggered1 = false } } else { this.aoUpIdx1 = -1 this.aoDownIdx1 = -1 this.aoUp1 = 0 this.aoDown1 = 0 this.aoUpTriggered1 = false this.aoDownTriggered1 = false } if (arrUp[arrLen - 2] > 0 && (arrUp[arrLen - 3] < 0 || (arrUp[arrLen - 4] < 0 && arrUp[arrLen - 3] == 0 && arrDown[arrLen - 3] == 0))) { if (arrLen - 2 != this.aoUpIdx2) { this.aoUpIdx2 = arrLen - 2 this.aoDownIdx2 = -1 this.aoUp2 = arrHigh[arrLen - 2] this.aoDown2 = 0 this.aoUpTriggered2 = false this.aoDownTriggered2 = false } } else if (arrDown[arrLen - 2] < 0 && (arrDown[arrLen - 3] > 0 || (arrDown[arrLen - 4] > 0 && arrUp[arrLen - 3] == 0 && arrDown[arrLen - 3] == 0))) { if (arrLen - 2 != this.aoDownIdx2) { this.aoUpIdx2 = -1 this.aoDownIdx2 = arrLen - 2 this.aoUp2 = 0 this.aoDown2 = arrLow[arrLen - 2] this.aoUpTriggered2 = false this.aoDownTriggered2 = false } } else { this.aoUpIdx2 = -1 this.aoDownIdx2 = -1 this.aoUp2 = 0 this.aoDown2 = 0 this.aoUpTriggered2 = false this.aoDownTriggered2 = false } var cursor = arrLen - 3 var latestPeakIdx1 = -1 var latestPeakIdx2 = -1 var arrData = [] var bContinue = true while (cursor >= 0) { if ((arrUp[cursor] > 0 && arrDown[cursor + 1] > 0) || (arrDown[cursor] > 0 && arrUp[cursor + 1] > 0) || (arrUp[cursor] > 0 && arrUp[cursor + 1] > 0) || (arrDown[cursor] > 0 && arrDown[cursor + 1] > 0) || (arrUp[cursor] < 0 && arrDown[cursor + 1] < 0) || (arrDown[cursor] < 0 && arrUp[cursor + 1] < 0) || (arrUp[cursor] < 0 && arrUp[cursor + 1] < 0) || (arrDown[cursor] < 0 && arrDown[cursor + 1] < 0)) { } else { bContinue = false } if (arrUp[cursor + 1] != 0) { arrData.push({ ao: arrUp[cursor + 1], idx: cursor + 1 }) } if (arrDown[cursor + 1] != 0) { arrData.push({ ao: arrDown[cursor + 1], idx: cursor + 1 }) } var arrDataLen = arrData.length if (arrDataLen > 1) { if (arrData[arrDataLen - 1].ao < 0) { if (arrDataLen == 2 && arrData[1].ao > arrData[0].ao) { break } else { if (arrDataLen > 2 && arrData[arrDataLen - 1].ao > arrData[arrDataLen - 2].ao && arrData[arrDataLen - 2].ao < arrData[arrDataLen - 3].ao) { if (latestPeakIdx1 != -1) { latestPeakIdx2 = arrData[arrDataLen - 2].idx break } else { latestPeakIdx1 = arrData[arrDataLen - 2].idx } } } } else { if (arrDataLen == 2 && arrData[1].ao < arrData[0].ao) { break } else { if (arrDataLen > 2 && arrData[arrDataLen - 1].ao < arrData[arrDataLen - 2].ao && arrData[arrDataLen - 2].ao > arrData[arrDataLen - 3].ao) { if (latestPeakIdx1 != -1) { latestPeakIdx2 = arrData[arrDataLen - 2].idx break } else { latestPeakIdx1 = arrData[arrDataLen - 2].idx } } } } } if (!bContinue) { break } cursor-- } if (latestPeakIdx2 != -1) { if (arrData[0].ao < 0 && arrDown[latestPeakIdx1] > arrDown[latestPeakIdx2]) { if (latestPeakIdx1 + 1 != this.aoUpIdx3) { this.aoUpIdx3 = latestPeakIdx1 + 1 this.aoDownIdx3 = -1 this.aoUp3 = arrHigh[latestPeakIdx1 + 1] this.aoDown3 = 0 this.aoUpTriggered3 = false this.aoDownTriggered3 = false } } else if (arrData[0].ao > 0 && arrUp[latestPeakIdx1] < arrUp[latestPeakIdx2]) { if (latestPeakIdx1 + 1 != this.aoDownIdx3) { this.aoUpIdx3 = -1 this.aoDownIdx3 = latestPeakIdx1 + 1 this.aoUp3 = 0 this.aoDown3 = arrLow[latestPeakIdx1 + 1] this.aoUpTriggered3 = false this.aoDownTriggered3 = false } } else { this.aoUpIdx3 = -1 this.aoDownIdx3 = -1 this.aoUp3 = 0 this.aoDown3 = 0 this.aoUpTriggered3 = false this.aoDownTriggered3 = false } } else { this.aoUpIdx3 = -1 this.aoDownIdx3 = -1 this.aoUp3 = 0 this.aoDown3 = 0 this.aoUpTriggered3 = false this.aoDownTriggered3 = false } }, checkAoSignal: function (currTick) { var signal1 = -1 var signal2 = -1 var signal3 = -1 if (this.aoUp1 > 0) { if (!this.aoUpTriggered1) { if (currTick > this.aoUp1) { this.aoUpTriggered1 = true signal1 = 1 } } } if (this.aoDown1 > 0) { if (!this.aoDownTriggered1) { if (currTick < this.aoDown1) { this.aoDownTriggered1 = true signal1 = 0 } } } if (this.aoUp2 > 0) { if (!this.aoUpTriggered2) { if (currTick > this.aoUp2) { this.aoUpTriggered2 = true signal2 = 1 } } } if (this.aoDown2 > 0) { if (!this.aoDownTriggered2) { if (currTick < this.aoDown2) { this.aoDownTriggered2 = true signal2 = 0 } } } if (this.aoUp3 > 0) { if (!this.aoUpTriggered3) { if (currTick > this.aoUp3) { this.aoUpTriggered3 = true signal3 = 1 } } } if (this.aoDown3 > 0) { if (!this.aoDownTriggered3) { if (currTick < this.aoDown3) { this.aoDownTriggered3 = true signal3 = 0 } } } return { signal1: signal1, signal2: signal2, signal3: signal3 } }, acUpIdx1: -1, acDownIdx1: -1, acUp1: 0, acDown1: 0, acUpTriggered1: false, acDownTriggered1: false, acUpIdx2: -1, acDownIdx2: -1, acUp2: 0, acDown2: 0, acUpTriggered2: false, acDownTriggered2: false, getAcSignal: function (arrUp, arrDown, arrHigh, arrLow) { var arrLen = arrHigh.length if (arrDown[arrLen - 4] != 0 && arrUp[arrLen - 3] != 0 && arrUp[arrLen - 2] > 0) { if (arrLen - 2 != this.acUpIdx1) { this.acUpIdx1 = arrLen - 2 this.acDownIdx1 = -1 this.acUp1 = arrHigh[arrLen - 2] this.acDown1 = 0 this.acUpTriggered1 = false this.acDownTriggered1 = false } } else if (arrUp[arrLen - 4] != 0 && arrDown[arrLen - 3] != 0 && arrDown[arrLen - 2] < 0) { if (arrLen - 2 != this.acDownIdx1) { this.acUpIdx1 = -1 this.acDownIdx1 = arrLen - 2 this.acUp1 = 0 this.acDown1 = arrLow[arrLen - 2] this.acUpTriggered1 = false this.acDownTriggered1 = false } } else { this.acUpIdx1 = -1 this.acDownIdx1 = -1 this.acUp1 = 0 this.acDown1 = 0 this.acUpTriggered1 = false this.acDownTriggered1 = false } if (arrDown[arrLen - 5] < 0 && arrUp[arrLen - 4] < 0 && arrUp[arrLen - 3] < 0 && arrUp[arrLen - 2] != 0) { if (arrLen - 2 != this.acUpIdx2) { this.acUpIdx2 = arrLen - 2 this.acDownIdx2 = -1 this.acUp2 = arrHigh[arrLen - 2] this.acDown2 = 0 this.acUpTriggered2 = false this.acDownTriggered2 = false } } else if (arrUp[arrLen - 5] > 0 && arrDown[arrLen - 4] > 0 && arrDown[arrLen - 3] > 0 && arrDown[arrLen - 2] != 0) { if (arrLen - 2 != this.acDownIdx2) { this.acUpIdx2 = -1 this.acDownIdx2 = arrLen - 2 this.acUp2 = 0 this.acDown2 = arrLow[arrLen - 2] this.acUpTriggered2 = false this.acDownTriggered2 = false } } else { this.acUpIdx2 = -1 this.acDownIdx2 = -1 this.acUp2 = 0 this.acDown2 = 0 this.acUpTriggered2 = false this.acDownTriggered2 = false } }, checkAcSignal: function (currTick) { var signal1 = -1 var signal2 = -1 if (this.acUp1 > 0) { if (!this.acUpTriggered1) { if (currTick > this.acUp1) { this.acUpTriggered1 = true signal1 = 1 } } } if (this.acDown1 > 0) { if (!this.acDownTriggered1) { if (currTick < this.acDown1) { this.acDownTriggered1 = true signal1 = 0 } } } if (this.acUp2 > 0) { if (!this.acUpTriggered2) { if (currTick > this.acUp2) { this.acUpTriggered2 = true signal2 = 1 } } } if (this.acDown2 > 0) { if (!this.acDownTriggered2) { if (currTick < this.acDown2) { this.acDownTriggered2 = true signal2 = 0 } } } return { signal1: signal1, signal2: signal2 } }, mapUpIdx: -1, mapDownIdx: -1, mapUp: 0, mapDown: 0, mapUpTriggered: false, mapDownTriggered: false, mapUpCnt: 0, mapDownCnt: 0, mapUpSl: 0, mapDownSl: 0, mapUpSlTriggered: false, mapDownSlTriggered: false, getMapSignal: function (arrAoUp, arrAoDown, arrAcUp, arrAcDown, arrClose, arrHigh, arrLow) { var arrLen = arrClose.length if (arrAoUp[arrLen - 2] != 0 && arrAcUp[arrLen - 2] != 0) { if (arrLen - 2 != this.mapUpIdx) { if (this.mapUpIdx == -1) { this.mapUpCnt = 1 } else { this.mapUpCnt++ } this.mapDownCnt = 0 this.mapUpIdx = arrLen - 2 this.mapDownIdx = -1 this.mapUp = arrClose[arrLen - 2] this.mapDown = 0 this.mapUpTriggered = false this.mapDownTriggered = false if (this.mapUpCnt >= 6) { this.mapUp = 0 this.mapUpTriggered = false this.mapUpSl = arrLow[arrLen - 2] this.mapUpSlTriggered = false } else { this.mapUpSl = 0 this.mapUpSlTriggered = false } this.mapDownSl = 0 this.mapDownSlTriggered = false } } else if (arrAoDown[arrLen - 2] != 0 && arrAcDown[arrLen - 2] != 0) { if (arrLen - 2 != this.mapDownIdx) { this.mapUpCnt = 0 if (this.mapDownIdx == -1) { this.mapDownCnt = 1 } else { this.mapDownCnt++ } this.mapUpIdx = -1 this.mapDownIdx = arrLen - 2 this.mapUp = 0 this.mapDown = arrClose[arrLen - 2] this.mapUpTriggered = false this.mapDownTriggered = false this.mapUpSl = 0 this.mapUpSlTriggered = false if (this.mapDownCnt >= 6) { this.mapDown = 0 this.mapDownTriggered = false this.mapDownSl = arrHigh[arrLen - 2] this.mapDownSlTriggered = false } else { this.mapDownSl = 0 this.mapDownSlTriggered = false } } } else { this.mapUpIdx = -1 this.mapDownIdx = -1 this.mapUp = 0 this.mapDown = 0 this.mapUpTriggered = false this.mapDownTriggered = false if (this.mapUpCnt >= 5) { this.mapUpSl = arrLow[arrLen - 2] this.mapUpSlTriggered = false } else { this.mapUpCnt = 0 this.mapUpSl = 0 this.mapUpSlTriggered = false } if (this.mapDownCnt >= 5) { this.mapDownSl = arrHigh[arrLen - 2] this.mapDownSlTriggered = false } else { this.mapDownCnt = 0 this.mapDownSl = 0 this.mapDownSlTriggered = false } } }, checkMapSignal: function (currTick, prevHigh, prevLow) { var signal = -1 if (this.mapUp > 0) { if (!this.mapUpTriggered) { if (currTick > this.mapUp) { if (this.mapUpCnt >= 5) { this.mapUp = 0 this.mapUpTriggered = false this.mapUpSl = prevLow this.mapUpSlTriggered = false } else { this.mapUpTriggered = true this.mapUpSl = 0 this.mapUpSlTriggered = false } this.mapDownSl = 0 this.mapDownSlTriggered = false signal = 1 } } } if (this.mapDown > 0) { if (!this.mapDownTriggered) { if (currTick < this.mapDown) { this.mapUpSl = 0 this.mapUpSlTriggered = false if (this.mapDownCnt >= 5) { this.mapDown = 0 this.mapDownTriggered = false this.mapDownSl = prevHigh this.mapDownSlTriggered = false } else { this.mapDownTriggered = true this.mapDownSl = 0 this.mapDownSlTriggered = false } signal = 0 } } } if (this.mapUpSl > 0) { if (!this.mapUpSlTriggered) { if (currTick < this.mapUpSl) { this.mapUpSlTriggered = true this.mapUpCnt = 0 signal = 3 } } } if (this.mapDownSl > 0) { if (!this.mapDownSlTriggered) { if (currTick > this.mapDownSl) { this.mapDownSlTriggered = true this.mapDownCnt = 0 signal = 2 } } } return signal }, alligatorUpIdx1: -1, alligatorDownIdx1: -1, alligatorUp1: 0, alligatorDown1: 0, alligatorUpTriggered1: false, alligatorDownTriggered1: false, alligatorUpBase1: 0, alligatorDownBase1: 0, alligatorUpIdx2: -1, alligatorDownIdx2: -1, alligatorUp2: 0, alligatorDown2: 0, alligatorUpTriggered2: false, alligatorDownTriggered2: false, alligatorUpBase2: 0, alligatorDownBase2: 0, alligatorUpIdx3: -1, alligatorDownIdx3: -1, alligatorUp3: 0, alligatorDown3: 0, alligatorUpTriggered3: false, alligatorDownTriggered3: false, alligatorUpBase3: 0, alligatorDownBase3: 0, getAlligatorSignal: function (arrHigh, arrLow, currLip, currJaw, currAoUp, currAoDown, currAcUp, currAcDown) { var arrLen = arrHigh.length if (this.alligatorUpIdx1 != 0) { if (this.alligatorUpBase1 > arrHigh[arrLen - 2]) { this.alligatorUpIdx1 = -1 this.alligatorUp1 = 0 this.alligatorUpTriggered1 = false this.alligatorUpBase1 = 0 } } if (this.alligatorDownIdx1 != 0) { if (this.alligatorDownBase1 < arrLow[arrLen - 2]) { this.alligatorDownIdx1 = -1 this.alligatorDown1 = 0 this.alligatorDownTriggered1 = false this.alligatorDownBase1 = 0 } } if (arrHigh[arrLen - 3] > arrHigh[arrLen - 2] && arrHigh[arrLen - 2] > currLip) { if (arrLen - 3 != this.alligatorUpIdx1) { this.alligatorUpIdx1 = arrLen - 3 this.alligatorUp1 = arrHigh[arrLen - 3] this.alligatorUpTriggered1 = false this.alligatorUpBase1 = arrHigh[arrLen - 2] } } else if (arrLow[arrLen - 3] < arrLow[arrLen - 2] && arrLow[arrLen - 2] < currLip) { if (arrLen - 3 != this.alligatorDownIdx1) { this.alligatorDownIdx1 = arrLen - 3 this.alligatorDown1 = arrLow[arrLen - 3] this.alligatorDownTriggered1 = false this.alligatorDownBase1 = arrLow[arrLen - 2] } } if (this.alligatorUpIdx2 != 0) { if (this.alligatorUpBase2 > arrHigh[arrLen - 2]) { this.alligatorUpIdx2 = -1 this.alligatorUp2 = 0 this.alligatorUpTriggered2 = false this.alligatorUpBase2 = 0 } } if (this.alligatorDownIdx2 != 0) { if (this.alligatorDownBase2 < arrLow[arrLen - 2]) { this.alligatorDownIdx2 = -1 this.alligatorDown2 = 0 this.alligatorDownTriggered2 = false this.alligatorDownBase2 = 0 } } if (arrHigh[arrLen - 4] > arrHigh[arrLen - 3] && arrHigh[arrLen - 3] > arrHigh[arrLen - 2] && arrHigh[arrLen - 2] < currJaw && ((currAoUp != 0 && currAcUp != 0) || (currAoUp != 0 && currAcDown != 0) || (currAoDown != 0 && currAcUp != 0))) { if (arrLen - 4 != this.alligatorUpIdx2) { this.alligatorUpIdx2 = arrLen - 4 this.alligatorUp2 = arrHigh[arrLen - 4] this.alligatorUpTriggered2 = false this.alligatorUpBase2 = arrHigh[arrLen - 2] } } else if (arrLow[arrLen - 4] < arrLow[arrLen - 3] && arrLow[arrLen - 3] < arrLow[arrLen - 2] && arrLow[arrLen - 2] > currJaw && ((currAoDown != 0 && currAcDown != 0) || (currAoUp != 0 && currAcDown != 0) || (currAoDown != 0 && currAcUp != 0))) { if (arrLen - 4 != this.alligatorDownIdx2) { this.alligatorDownIdx2 = arrLen - 4 this.alligatorDown2 = arrLow[arrLen - 4] this.alligatorDownTriggered2 = false this.alligatorDownBase2 = arrLow[arrLen - 2] } } if (this.alligatorUpIdx3 != 0) { if (this.alligatorUpBase3 > arrHigh[arrLen - 2]) { this.alligatorUpIdx3 = -1 this.alligatorUp3 = 0 this.alligatorUpTriggered3 = false this.alligatorUpBase3 = 0 } } if (this.alligatorDownIdx3 != 0) { if (this.alligatorDownBase3 < arrLow[arrLen - 2]) { this.alligatorDownIdx3 = -1 this.alligatorDown3 = 0 this.alligatorDownTriggered3 = false this.alligatorDownBase3 = 0 } } if (arrHigh[arrLen - 6] > arrHigh[arrLen - 5] && arrHigh[arrLen - 5] > arrHigh[arrLen - 4] && arrHigh[arrLen - 4] > arrHigh[arrLen - 3] && arrHigh[arrLen - 3] > arrHigh[arrLen - 2] && arrHigh[arrLen - 2] < currJaw && currAoDown != 0 && currAcDown != 0) { if (arrLen - 6 != this.alligatorUpIdx3) { this.alligatorUpIdx3 = arrLen - 6 this.alligatorUp3 = arrHigh[arrLen - 6] this.alligatorUpTriggered3 = false this.alligatorUpBase3 = arrHigh[arrLen - 2] } } else if (arrLow[arrLen - 6] < arrLow[arrLen - 5] && arrLow[arrLen - 5] < arrLow[arrLen - 4] && arrLow[arrLen - 4] < arrLow[arrLen - 3] && arrLow[arrLen - 3] < arrLow[arrLen - 2] && arrLow[arrLen - 2] > currJaw && currAoUp != 0 && currAcUp != 0) { if (arrLen - 6 != this.alligatorDownIdx3) { this.alligatorDownIdx3 = arrLen - 6 this.alligatorDown3 = arrLow[arrLen - 6] this.alligatorDownTriggered3 = false this.alligatorDownBase3 = arrLow[arrLen - 2] } } }, checkAlligatorSignal: function (currTick) { var signal1 = -1 var signal2 = -1 var signal3 = -1 if (this.alligatorUp1 > 0) { if (!this.alligatorUpTriggered1) { if (currTick > this.alligatorUp1) { this.alligatorUpTriggered1 = true signal1 = 1 } } } if (this.alligatorDown1 > 0) { if (!this.alligatorDownTriggered1) { if (currTick < this.alligatorDown1) { this.alligatorDownTriggered1 = true signal1 = 0 } } } if (this.alligatorUp2 > 0) { if (!this.alligatorUpTriggered2) { if (currTick > this.alligatorUp2) { this.alligatorUpTriggered2 = true signal2 = 1 } } } if (this.alligatorDown2 > 0) { if (!this.alligatorDownTriggered2) { if (currTick < this.alligatorDown2) { this.alligatorDownTriggered2 = true signal2 = 0 } } } if (this.alligatorUp3 > 0) { if (!this.alligatorUpTriggered3) { if (currTick > this.alligatorUp3) { this.alligatorUpTriggered3 = true signal3 = 1 } } } if (this.alligatorDown3 > 0) { if (!this.alligatorDownTriggered3) { if (currTick < this.alligatorDown3) { this.alligatorDownTriggered3 = true signal3 = 0 } } } return { signal1: signal1, signal2: signal2, signal3: signal3 } }, checkCloseSignal: function (arrTeeth, arrClose) { var arrLen = arrClose.length if (arrTeeth[arrLen - 7] > arrClose[arrLen - 2] && arrClose[arrLen - 3] >= arrTeeth[arrLen - 8]) { return 3 } if (arrTeeth[arrLen - 7] < arrClose[arrLen - 2] && arrClose[arrLen - 3] <= arrTeeth[arrLen - 8]) { return 2 } return -1 }, trend: -1 } }, function (context) { // Deinit() }, function (context) { // OnTick() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = getEAParameter(context, "symbolName") var volume = getEAParameter(context, "volume") var arrTime = getData(context, context.chartHandle, DATA_NAME.TIME) var arrHigh = getData(context, context.chartHandle, DATA_NAME.HIGH) var arrLow = getData(context, context.chartHandle, DATA_NAME.LOW) var arrClose = getData(context, context.chartHandle, DATA_NAME.CLOSE) var arrTeeth = getData(context, context.alligatorHandle, "teeth") var arrLips = getData(context, context.alligatorHandle, "lips") var arrJaws = getData(context, context.alligatorHandle, "jaws") var arrUp = getData(context, context.fractalsHandle, "fractalsUp") var arrDown = getData(context, context.fractalsHandle, "fractalsDown") var arrAoUp = getData(context, context.aoHandle, "up") var arrAoDown = getData(context, context.aoHandle, "down") var arrAcUp = getData(context, context.acHandle, "up") var arrAcDown = getData(context, context.acHandle, "down") var arrLen = arrTime.length if (200 >= arrLen) throw new Error("No enough data.") var bGetSignals = false if (typeof context.currTime == "undefined") { context.currTime = arrTime[arrTime.length - 1] bGetSignals = true } else if (context.currTime != arrTime[arrTime.length - 1]) { context.currTime = arrTime[arrTime.length - 1] bGetSignals = true } if (bGetSignals) { context.chaos.getFractalsSignal(arrUp, arrDown) context.chaos.getAoSignal(arrAoUp, arrAoDown, arrHigh, arrLow) context.chaos.getAcSignal(arrAcUp, arrAcDown, arrHigh, arrLow) context.chaos.getMapSignal(arrAoUp, arrAoDown, arrAcUp, arrAcDown, arrClose, arrHigh, arrLow) context.chaos.getAlligatorSignal(arrHigh, arrLow, arrLips[arrLen - 2], arrJaws[arrLen - 2], arrAoUp[arrLen - 2], arrAoDown[arrLen - 2], arrAcUp[arrLen - 2], arrAcDown[arrLen - 2]) } var signal = -1 var fractalsSignal = context.chaos.checkFractalsSignal(arrTeeth, arrClose[arrLen - 1]) if (fractalsSignal != -1) { signal = fractalsSignal context.chaos.trend = fractalsSignal } if (context.chaos.trend == -1) { return } var aoSignal = context.chaos.checkAoSignal(arrClose[arrLen - 1]) if (aoSignal.signal1 == context.chaos.trend) { signal = context.chaos.trend } if (aoSignal.signal2 == context.chaos.trend) { signal = context.chaos.trend } if (aoSignal.signal3 == context.chaos.trend) { signal = context.chaos.trend } var acSignal = context.chaos.checkAcSignal(arrClose[arrLen - 1]) if (acSignal.signal1 == context.chaos.trend) { signal = context.chaos.trend } if (acSignal.signal2 == context.chaos.trend) { signal = context.chaos.trend } var mapSignal = context.chaos.checkMapSignal(arrClose[arrLen - 1], arrHigh[arrLen - 2], arrLow[arrLen - 2]) if (mapSignal == context.chaos.trend) { signal = context.chaos.trend } var alligatorSignal = context.chaos.checkAlligatorSignal(arrClose[arrLen - 1]) if (alligatorSignal.signal1 == context.chaos.trend) { signal = context.chaos.trend } if (alligatorSignal.signal2 == context.chaos.trend) { signal = context.chaos.trend } if (alligatorSignal.signal3 == context.chaos.trend) { signal = context.chaos.trend } var closeSignal = context.chaos.checkCloseSignal(arrTeeth, arrClose) if (closeSignal != -1) { signal = closeSignal } if ((mapSignal == 3 && context.chaos.trend == 1) || (mapSignal == 2 && context.chaos.trend == 0)) { signal = mapSignal } if (signal == 1) { popupMessage("You received an OPEN LONG signal!") } else if (signal == 0) { popupMessage("You received an OPEN SHORT signal!") } else if (signal == 3) { if (bGetSignals) { popupMessage("You received a CLOSE LONG signal!") } } else if (signal == 2) { if (bGetSignals) { popupMessage("You received a CLOSE SHORT signal!") } } }, function (context) { // OnTransaction() } ) ================================================ FILE: EA/Chaos/intro.txt ================================================ EA based on Trading Chaos(Bill Williams' book). All of the strategies described in the book have been implemented. Additionally, you may utilize “extra_mfi” as a supplementary tool. ================================================ FILE: EA/CopyTrading/README.md ================================================ This is just an example. ================================================ FILE: EA/CopyTrading/copy_trading_for_oanda.js ================================================ registerEA( "copy_trading_for_oanda", "An EA to copy trading for Oanda(v1.02)", [], function (context) { // Init() }, function (context) { // Deinit() }, function (context) { // OnTick() }, function (context) { // OnTransaction() if (typeof window.pluginForOanda != "undefined") { var transType = getLatestTransType(context) if (transType == "Open Trade") { var trade = getLatestTrans(context) var tradeSymbolName = getSymbolName(trade) var tradeOrderType = getOrderType(trade) var tradeLots = getOpenLots(trade) if (tradeOrderType == ORDER_TYPE.OP_BUY || tradeOrderType == ORDER_TYPE.OP_BUYLIMIT || tradeOrderType == ORDER_TYPE.OP_BUYSTOP) { window.pluginForOanda.sendOrder(tradeSymbolName, ORDER_TYPE.OP_BUY, tradeLots) } else if (tradeOrderType == ORDER_TYPE.OP_SELL || tradeOrderType == ORDER_TYPE.OP_SELLLIMIT || tradeOrderType == ORDER_TYPE.OP_SELLSTOP) { window.pluginForOanda.sendOrder(tradeSymbolName, ORDER_TYPE.OP_SELL, tradeLots) } } else if (transType == "Trade Closed") { var trade = getLatestTrans(context) var tradeSymbolName = getSymbolName(trade) var tradeOrderType = getOrderType(trade) var tradeLots = getOpenLots(trade) if (tradeOrderType == ORDER_TYPE.OP_BUY || tradeOrderType == ORDER_TYPE.OP_BUYLIMIT || tradeOrderType == ORDER_TYPE.OP_BUYSTOP) { window.pluginForOanda.sendOrder(tradeSymbolName, ORDER_TYPE.OP_SELL, tradeLots) } else if (tradeOrderType == ORDER_TYPE.OP_SELL || tradeOrderType == ORDER_TYPE.OP_SELLLIMIT || tradeOrderType == ORDER_TYPE.OP_SELLSTOP) { window.pluginForOanda.sendOrder(tradeSymbolName, ORDER_TYPE.OP_BUY, tradeLots) } } } } ) ================================================ FILE: EA/CopyTrading/copy_trading_for_oanda_guide.txt ================================================ Use Case: A provides signals, B follows the signals from A to copy trade. A's account is a Fintechee-based account, B's account is an Oanda-based account. How to do? 1. A shares A's investor password with B. Please note, enabling investor mode is not required for this step. If you enable investor mode, then everyone can check your trading records. If you disable investor mode(disabled by default), then only the followers that know your investor password can check your trading records. 2. B signs into both accounts. B signs into A's account by entering A's investor password. B signs into B's Oanda-based account by launching an EA named plugin_for_oanda. You can get plugin_for_oanda on Fintechee's Github repo: https://github.com/fintechees/Expert-Advisor-Studio/blob/master/EA/Plugin-for-Oanda/plugin_for_oanda.js Oanda issues a token as login credential. So, B needs to input it into the corresponding parameter for oanda_loader. 3. B launches copy_trading_for_oanda via Fintechee WEB Trader. You can get copy_trading_for_oanda on Fintechee's Github repo: https://github.com/fintechees/Expert-Advisor-Studio/blob/master/EA/CopyTrading/copy_trading_for_oanda.js There are no parameters because the EA will follow all the signals that it receives and trade via B's Oanda account. B has logged into A's account in the investor mode, so all the signals that A issues will be seen by B. The EA will send orders via the plugin_for_oanda launched in the 2nd step. Done! ================================================ FILE: EA/CopyTrading/copy_trading_locally.js ================================================ registerEA( "copy_trading_locally", "A simple EA to copy trading locally(v1.01)", [{ name: "fromAccountId", value: "XXXXXXXXXX", // e.g. account id:1066149, investor password: 1 required: true, type: "String", range: null, step: null }, { name: "toAccountId", value: "XXXXXXXXXX", required: true, type: "String", range: null, step: null }], function (context) { // Init() }, function (context) { // Deinit() }, function (context) { // OnTick() }, function (context) { // OnTransaction() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var fromAccountId = getEAParameter(context, "fromAccountId") var toAccountId = getEAParameter(context, "toAccountId") var volume = 0.01 var transType = getLatestTransType(context) if (transType == "Open Trade" && tradeAccountId == fromAccountId) { var trade = getLatestTrans(context) var tradeAccountId = getAccountId(trade) var tradeSymbolName = getSymbolName(trade) var tradeOrderType = getOrderType(trade) if (tradeOrderType == ORDER_TYPE.OP_BUY || tradeOrderType == ORDER_TYPE.OP_BUYLIMIT || tradeOrderType == ORDER_TYPE.OP_BUYSTOP) { sendOrder(brokerName, toAccountId, tradeSymbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (tradeOrderType == ORDER_TYPE.OP_SELL || tradeOrderType == ORDER_TYPE.OP_SELLLIMIT || tradeOrderType == ORDER_TYPE.OP_SELLSTOP) { sendOrder(brokerName, toAccountId, tradeSymbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } } else if (transType == "Trade Closed" && tradeAccountId == fromAccountId) { var trade = getLatestTrans(context) var tradeAccountId = getAccountId(trade) var tradeSymbolName = getSymbolName(trade) var tradeOrderType = getOrderType(trade) var tradeOrderType2 = null if (tradeOrderType == ORDER_TYPE.OP_BUY || tradeOrderType == ORDER_TYPE.OP_BUYLIMIT || tradeOrderType == ORDER_TYPE.OP_BUYSTOP) { tradeOrderType2 = ORDER_TYPE.OP_BUY } else if (tradeOrderType == ORDER_TYPE.OP_SELL || tradeOrderType == ORDER_TYPE.OP_SELLLIMIT || tradeOrderType == ORDER_TYPE.OP_SELLSTOP) { tradeOrderType2 = ORDER_TYPE.OP_SELL } var count = getOpenTradesListLength(context) var tradeId = null for (var i = count - 1; i >= 0; i--) { var openTrade = getOpenTrade(context, i) var accountId = getAccountId(openTrade) var symbolName = getSymbolName(openTrade) var orderType = getOrderType(openTrade) if (accountId == toAccountId && symbolName == tradeSymbolName && tradeOrderType2 == orderType) { tradeId = getTradeId(openTrade) break } } if (tradeId != null) { closeTrade(brokerName, toAccountId, tradeId, 0, 0) } else { if (tradeOrderType2 == ORDER_TYPE.OP_BUY) { sendOrder(brokerName, toAccountId, tradeSymbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else if (tradeOrderType2 == ORDER_TYPE.OP_SELL) { sendOrder(brokerName, toAccountId, tradeSymbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } } } }) ================================================ FILE: EA/CopyTrading/copy_trading_locally_guide.txt ================================================ Use Case: A provides signals, B follows the signals from A to copy trade. Both accounts are Fintechee-based. How to do? 1. A shares A's investor password with B. Please note, enabling investor mode is not required for this step. If you enable investor mode, then everyone can check your trading records. If you disable investor mode(disabled by default), then only the followers that know your investor password can check your trading records. 2. B signs into both accounts. B signs into A's account by entering A's investor password. B signs into B's own account by entering B's password. 3. B launches copy_trading_locally via Fintechee WEB Trader. If copy_trading_locally doesn't exist, you can get it on Fintechee's Github repo: https://github.com/fintechees/Expert-Advisor-Studio/blob/master/EA/CopyTrading/copy_trading_locally.js Copy the source codes and paste them into Fintechee WEB Trader's Javascript console and run it. Then you can find it listed on the EA list and launch it. There are two parameters: fromAccountId and toAccountId. B sets fromAccountId to A's account ID and sets toAccountId to B's account ID. Done! ================================================ FILE: EA/Martingale/improved_martingale.js ================================================ registerEA( "improved_martingale", "An EA based on an improved Martingale algorithm(v1.0)", [{ name: "diffPrice", value: 0.002, required: true, type: PARAMETER_TYPE.NUMBER, range: [0, 100] }, { name: "diffPrice2", value: 0.001, required: true, type: PARAMETER_TYPE.NUMBER, range: [0, 100] }], function(context) { // Init() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" getQuotes(context, brokerName, accountId, symbolName) context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.H1) context.maxCost = Number.MAX_VALUE context.maxPos = 0 context.openTrades = [] context.res = [] }, function(context) { // Deinit() }, function(context) { // OnTick() var arrTime = getData(context, context.chartHandle, DATA_NAME.TIME) var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" var diffPrice = getEAParameter(context, "diffPrice") var diffPrice2 = getEAParameter(context, "diffPrice2") var signal = Math.random() >= 0.5 ? 1 : 0 // This EA is created mainly to show you how to improve Martingale algo, so the signals are generated by random. Please replace the signal generator with your own algo. var ask = null var bid = null try { ask = getAsk(context, brokerName, accountId, symbolName) bid = getBid(context, brokerName, accountId, symbolName) } catch (e) { // This try-catch is used to bypass the "error throw" when you start the EA too early to call getAsk or getBid(at that time, bid or ask may be not ready yet.) printErrorMessage(e.message) return } var count = getOpenTradesListLength(context) var countL = 0 var countS = 0 var totalPLL = 0.0 var totalPLS = 0.0 var highPriceL = -Number.MAX_VALUE var lowPriceL = Number.MAX_VALUE var highPriceS = -Number.MAX_VALUE var lowPriceS = Number.MAX_VALUE for (var i = count - 1; i >= 0; i--) { var openTrade = getOpenTrade(context, i) var openPrice = getOpenPrice(openTrade) if (getOrderType(openTrade) == ORDER_TYPE.OP_BUY) { countL++ totalPLL += getUnrealizedPL(openTrade) if (openPrice > highPriceL) highPriceL = openPrice if (openPrice < lowPriceL) lowPriceL = openPrice } if (getOrderType(openTrade) == ORDER_TYPE.OP_SELL) { countS++ totalPLS += getUnrealizedPL(openTrade) if (openPrice > highPriceS) highPriceS = openPrice if (openPrice < lowPriceS) lowPriceS = openPrice } } if (totalPLL + totalPLS < context.maxCost) { context.maxCost = totalPLL + totalPLS } if (Math.abs(countL - countS) > Math.abs(context.maxPos)) { context.maxPos = countL - countS } if (typeof context.currTime == "undefined") { context.currTime = arrTime[arrTime.length - 1] } else if (context.currTime != arrTime[arrTime.length - 1]) { context.currTime = arrTime[arrTime.length - 1] } else { return } var arrClose = getData(context, context.chartHandle, DATA_NAME.CLOSE) var volume = 0.01 if (countL == 0 && countS == 0) { if (signal == 1) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } } else if (((countL + countS) > 1 && (totalPLL + totalPLS) > 0.1 * (countL + countS)) || (countL == 1 && countS == 0 && signal == 0 && (arrClose[arrClose.length - 1] - highPriceL) > diffPrice) || (countL == 0 && countS == 1 && signal == 1 && (lowPriceS - arrClose[arrClose.length - 1]) > diffPrice)) { var pos = Math.abs(countL - countS) if (typeof context.res[pos] == "undefined") { context.res[pos] = 1 } else { context.res[pos]++ } for (var i in context.res) { printMessage(i + ", " + context.res[i]) } printMessage("Pos: " + (countL - countS) + ", Unrealized PL: " + (totalPLL + totalPLS) + ", Max Cost: " + context.maxCost + ", Max Pos: " + context.maxPos) for (var i = count - 1; i >= 0; i--) { var openTrade = getOpenTrade(context, i) closeTrade(brokerName, accountId, getTradeId(openTrade), 0, 0) } } else if (countL == 1 && countS == 0 && signal == 0 && (highPriceL - arrClose[arrClose.length - 1]) > diffPrice) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL == 0 && countS == 1 && signal == 1 && (arrClose[arrClose.length - 1] - lowPriceS) > diffPrice) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && highPriceL > highPriceS && (arrClose[arrClose.length - 1] - highPriceL) > diffPrice && lowPriceL > lowPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && highPriceS > highPriceL && (arrClose[arrClose.length - 1] - highPriceS) > diffPrice && lowPriceL < lowPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && lowPriceL > lowPriceS && (lowPriceS - arrClose[arrClose.length - 1]) > diffPrice && highPriceL > highPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && lowPriceS > lowPriceL && (lowPriceL - arrClose[arrClose.length - 1]) > diffPrice && highPriceL < highPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && highPriceL > highPriceS && (arrClose[arrClose.length - 1] - highPriceL) > diffPrice2 && lowPriceL < lowPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && highPriceS > highPriceL && (arrClose[arrClose.length - 1] - highPriceS) > diffPrice2 && lowPriceL > lowPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && lowPriceL > lowPriceS && (lowPriceS - arrClose[arrClose.length - 1]) > diffPrice2 && highPriceL < highPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (countL > 0 && countS > 0 && lowPriceS > lowPriceL && (lowPriceL - arrClose[arrClose.length - 1]) > diffPrice2 && highPriceL > highPriceS) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } }, function(context) { // OnTransaction() } ) ================================================ FILE: EA/Martingale/improved_martingale.txt ================================================ Usually, Martingale strategy involves doubling the bet once a loss occurs and engaging in one-sided trading. In contrast, the “improved_martingale” strategy is a double-sided trading strategy. If losses continue to accrue, profits can still be made on one side. This means that the profit on one side can help reduce the overall loss risk. ================================================ FILE: EA/Martingale/sample_martingale.js ================================================ registerEA( "sample_martingale", "A test EA based on Martingale algorithm(v1.03)", [{ // parameters name: "period", value: 5, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] }], function (context) { // Init() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1) var period = getEAParameter(context, "period") context.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "sma", [{ name: "period", value: period }]) }, function (context) { // Deinit() }, function (context) { // OnTick() var arrTime = getData(context, context.chartHandle, DATA_NAME.TIME) if (typeof context.currTime == "undefined") { context.currTime = arrTime[arrTime.length - 1] } else if (context.currTime != arrTime[arrTime.length - 1]) { context.currTime = arrTime[arrTime.length - 1] } else { return } var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" var count = getOpenTradesListLength(context) var totalPL = 0.0 var highPrice = 0.0 var lowPrice = 100000000.0 var orientation = null for (var i = count - 1; i >= 0; i--) { var openTrade = getOpenTrade(context, i) totalPL += getUnrealizedPL(openTrade) var openPrice = getOpenPrice(openTrade) if (openPrice > highPrice) highPrice = openPrice if (openPrice < lowPrice) lowPrice = openPrice if (getOrderType(openTrade) == ORDER_TYPE.OP_BUY) orientation = ORDER_TYPE.OP_BUY if (getOrderType(openTrade) == ORDER_TYPE.OP_SELL) orientation = ORDER_TYPE.OP_SELL } var arrClose = getData(context, context.chartHandle, DATA_NAME.CLOSE) var arrSma = getData(context, context.indiHandle, "sma") var volume = 0.01 if (count > 0 && totalPL > 0.1 * count) { for (var i = count - 1; i >= 0; i--) { var openTrade = getOpenTrade(context, i) closeTrade(brokerName, accountId, getTradeId(openTrade), 0, 0) } } else if (count == 0) { if (arrClose[arrClose.length - 3] < arrSma[arrSma.length - 3] && arrClose[arrClose.length - 2] > arrSma[arrSma.length - 2]) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } else if (arrClose[arrClose.length - 3] > arrSma[arrSma.length - 3] && arrClose[arrClose.length - 2] < arrSma[arrSma.length - 2]) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } } else { if (orientation == ORDER_TYPE.OP_BUY && (lowPrice - arrClose[arrClose.length - 1]) > 0.0005) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "", 0, 0) } if (orientation == ORDER_TYPE.OP_SELL && (arrClose[arrClose.length - 1] - highPrice) > 0.0005) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0) } } }, function (context) { // OnTransaction() printMessage("test OnTransaction: " + getLatestTransId(context) + " " + getLatestTransType(context)) } ) ================================================ FILE: EA/NeuralNetwork/nn_example.js ================================================ // Please check this post to know how to use this EA: https://www.fintecher.org/daily-trading/added-genetic-algorithm-for-trading.html registerEA( "nn_example", "A test EA to run neuron model for XOR(v1.0)", [ // hidden layer(1st neuron) {name: "h11", value: 20, required: true, type: "Number", range: [-100, 100], step: 10}, {name: "h12", value: 20, required: true, type: "Number", range: [-100, 100], step: 10}, {name: "b1", value: -10, required: true, type: "Number", range: [-100, 100], step: 10}, // hidden layer(2nd neuron) {name: "h21", value: -20, required: true, type: "Number", range: [-100, 100], step: 10}, {name: "h22", value: -20, required: true, type: "Number", range: [-100, 100], step: 10}, {name: "b2", value: 30, required: true, type: "Number", range: [-100, 100], step: 10}, // output layer {name: "o1", value: 20, required: true, type: "Number", range: [-100, 100], step: 10}, {name: "o2", value: 20, required: true, type: "Number", range: [-100, 100], step: 10}, {name: "b", value: -30, required: true, type: "Number", range: [-100, 100], step: 10}, ], function (context) { // Init() // Please don't remove the source codes below, they are required to make an EA get boosted var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" getQuotes (context, brokerName, accountId, symbolName) }, function (context) { // Deinit() var h11 = getEAParameter(context, "h11") // weight var h12 = getEAParameter(context, "h12") // weight var b1 = getEAParameter(context, "b1") // bias var h21 = getEAParameter(context, "h21") var h22 = getEAParameter(context, "h22") var b2 = getEAParameter(context, "b2") var o1 = getEAParameter(context, "o1") // weight var o2 = getEAParameter(context, "o2") // weight var b = getEAParameter(context, "b") // bias var sigmoid = function (t) { return 1 / (1 + Math.pow(Math.E, -t)) } var nn = function (p1, p2) { return sigmoid(o1 * sigmoid(h11 * p1 + h12 * p2 + b1) + o2 * sigmoid(h21 * p1 + h22 * p2 + b2) + b) } var error = 0 error += nn(1, 1) error += 1 - nn(1, 0) error += 1 - nn(0, 1) error += nn(0, 0) setOptimizationResult(context, -error) printMessage("error: " + error + ", " + Math.round(nn(1, 1)) + " " + Math.round(nn(1, 0)) + " " + Math.round(nn(0, 1)) + " " + Math.round(nn(0, 0))) }, function (context) { // OnTick() }) ================================================ FILE: EA/NeuralNetwork/sample_run_neuron_model.js ================================================ registerEA( "sample_run_neuron_model", "A test EA to run neuron model(v1.04)", [{ // parameters name: "period", value: 20, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] },{ name: "inputNum", value: 20, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] },{ name: "threshold", value: 0.3, required: true, type: PARAMETER_TYPE.NUMBER, range: [0, 1] },{ name: "takeProfit", value: 0.0001, required: true, type: PARAMETER_TYPE.NUMBER, range: [0, 100] }], function (context) { // Init() // We use localstorage.reservedZone to store the neural network. // Please don't change the name "reservedZone" or your data stored in this zone will be removed while the version is updated. if (typeof localStorage.reservedZone == "undefined") return var reservedZone = JSON.parse(localStorage.reservedZone) if (typeof reservedZone.sample_training_neuron_model == "undefined") return context.myPerceptron = synaptic.Network.fromJSON(reservedZone.sample_training_neuron_model) var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" getQuotes (context, brokerName, accountId, symbolName) context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1) var period = getEAParameter(context, "period") context.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "rsi", [{ name: "period", value: period }]) }, function (context) { // Deinit() }, function (context) { // OnTick() var arrTime = getData(context, context.chartHandle, DATA_NAME.TIME) if (typeof context.currTime == "undefined") { context.currTime = arrTime[arrTime.length - 1] } else if (context.currTime != arrTime[arrTime.length - 1]) { context.currTime = arrTime[arrTime.length - 1] } else { return } var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" var period = getEAParameter(context, "period") var inputNum = getEAParameter(context, "inputNum") var threshold = getEAParameter(context, "threshold") var takeProfit = getEAParameter(context, "takeProfit") var arrRsi = getData(context, context.indiHandle, "rsi") if (inputNum + period - 1 > arrRsi.length) throw new Error("No enough data.") var input = [] for (var i = arrRsi.length - inputNum - 1; i < arrRsi.length - 1; i++) { input.push(arrRsi[i] / 100) } var result = context.myPerceptron.activate(input)[0] printMessage(result) var ask = null var bid = null var volume = 0.01 try { ask = getAsk(context, brokerName, accountId, symbolName) bid = getBid(context, brokerName, accountId, symbolName) } catch (e) { // This try-catch is used to bypass the "error throw" when you start the EA too early to call getAsk or getBid(at that time, bid or ask may be not ready yet.) printErrorMessage(e.message) return } if (result < 0.5 - threshold) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, ask+takeProfit, bid-3*takeProfit, "", 0, 0) } else if (result > 0.5 + threshold) { sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, bid-takeProfit, ask+3*takeProfit, "", 0, 0) } } ) ================================================ FILE: EA/NeuralNetwork/sample_training_neuron_model.js ================================================ registerEA( "sample_training_neuron_model", "A test EA to train neuron model(v1.03)", [{ // parameters name: "period", value: 20, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] },{ name: "inputNum", value: 20, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] },{ name: "hiddenNum", value: 50, required: true, type: PARAMETER_TYPE.INTEGER, range: [1, 100] },{ name: "diffPrice", value: 0.0001, required: true, type: PARAMETER_TYPE.NUMBER, range: [0, 10] }], function (context) { // Init() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var symbolName = "EUR/USD" context.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1) var period = getEAParameter(context, "period") context.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "rsi", [{ name: "period", value: period }]) }, function (context) { // Deinit() var period = getEAParameter(context, "period") var inputNum = getEAParameter(context, "inputNum") var hiddenNum = getEAParameter(context, "hiddenNum") var arrOpen = getData(context, context.chartHandle, DATA_NAME.OPEN) var arrClose = getData(context, context.chartHandle, DATA_NAME.CLOSE) var arrRsi = getData(context, context.indiHandle, "rsi") if (arrRsi.length <= period + 1) return if (inputNum + period - 1 > arrRsi.length) throw new Error("No enough data.") // extend the prototype chain Perceptron.prototype = new synaptic.Network() Perceptron.prototype.constructor = Perceptron var myPerceptron = new Perceptron(inputNum, hiddenNum, 1) var myTrainer = new synaptic.Trainer(myPerceptron) var diffPrice = getEAParameter(context, "diffPrice") var trainingSet = [] var longCount = 0 var shortCount = 0 for (var i = period - 1; i < arrRsi.length - inputNum; i++) { if (arrClose[i * inputNum + inputNum] - arrOpen[i * inputNum + inputNum] > diffPrice) { var input = [] for (var j = 0; j < inputNum; j++) { input.push(arrRsi[i * inputNum + j] / 100) } trainingSet.push({ input: input, output: [0] }) longCount++ } else if (arrOpen[i * inputNum + inputNum] - arrClose[i * inputNum + inputNum] > diffPrice) { var input = [] for (var j = 0; j < inputNum; j++) { input.push(arrRsi[i * inputNum + j] / 100) } trainingSet.push({ input: input, output: [1] }) shortCount++ } } myTrainer.train(trainingSet) // We use localstorage.reservedZone to store the neural network. // Please don't change the name "reservedZone" or your data stored in this zone will be removed while the version is updated. if (typeof localStorage.reservedZone == "undefined") { localStorage.reservedZone = JSON.stringify({sample_training_neuron_model: myPerceptron.toJSON()}) } else { var reservedZone = JSON.parse(localStorage.reservedZone) reservedZone.sample_training_neuron_model = myPerceptron.toJSON() localStorage.reservedZone = JSON.stringify(reservedZone) } printMessage(longCount + ", " + shortCount) printMessage(JSON.stringify(trainingSet)) printMessage(JSON.stringify(myPerceptron.toJSON())) }, function (context) { // OnTick() } ) ================================================ FILE: EA/NeuralNetwork/usage.txt ================================================ “sample_training_neuron_model” and “sample_run_neuron_model” are two neural network-based EAs that must be used together. One cannot function without the other. “sample_training_neuron_model” trains the model, while “sample_run_neuron_model” generates signals based on the model trained by “sample_training_neuron_model”. To help understand how a neural network works, we have included a simple example called “nn_example”. The algorithm implemented in this folder is based on Synaptic, an AI framework. Tensorflow, a more advanced framework, runs convolutional neural networks. For more details on Tensorflow, refer to plugin_for_tensorflow. ================================================ FILE: EA/Oldie/README.md ================================================ This folder contains the deprecated programs. ================================================ FILE: EA/Oldie/README.txt ================================================ This folder contains deprecated programs. ================================================ FILE: EA/Oldie/fixapi_oanda_arbitrage.js ================================================ // Deprecated. A new version has been released. Please refer to EA/fintechee_external_arbitrage.js. registerEA( "fixapi_oanda_arbitrage", "A test EA to trade arbitrage based on the price difference between FIX API and Oanda(v1.10)", [{ name: "autoLoad", value: true, required: true, type: PARAMETER_TYPE.BOOLEAN, range: null }, { name: "autoSave", value: true, required: true, type: PARAMETER_TYPE.BOOLEAN, range: null }, { name: "backgroundColor", value: "#dfc29a", required: true, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) window.autoLoadArbitrageStats = getEAParameter(context, "autoLoad") window.autoSaveArbitrageStats = getEAParameter(context, "autoSave") window.arbitrageBgColor = getEAParameter(context, "backgroundColor") window.latestDay = new Date().getDay() if (typeof window.oandaLoaded != "undefined" && window.oandaLoaded) { window.latestFIXTickTime = new Date().getTime() window.latestSaveTime = window.latestFIXTickTime if (typeof window.arbitrageStatistics == "undefined") { for (var i in window.oandaApiLoader.oandaQuotes) { getQuotes(context, brokerName, accountId, i.replace("_", "/")) } window.arbitrageStatistics = [] for (var i in window.oandaApiLoader.oandaQuotes) { window.arbitrageStatistics[i] = { h: [], h2: [], ph: [], ph2: [] } for (var j = 0; j <= 23; j++) { window.arbitrageStatistics[i].h.push(0) window.arbitrageStatistics[i].h2.push(0) window.arbitrageStatistics[i].ph.push(0) window.arbitrageStatistics[i].ph2.push(0) } } window.loadArbitrageStatistics = function (arbitrageStatistics) { if (typeof localStorage.reservedZone != "undefined") { var reservedZone = JSON.parse(localStorage.reservedZone) if (typeof reservedZone.arbitrageStatistics != "undefined" && typeof reservedZone.arbitrageStatistics.statistics != "undefined") { if (new Date(reservedZone.arbitrageStatistics.latestSaveTime).getDay() < window.latestDay) { for (var i in reservedZone.arbitrageStatistics.statistics) { var statistics = reservedZone.arbitrageStatistics.statistics[i] arbitrageStatistics[statistics.symbolName] = { h: [], h2: [], ph: statistics.h, ph2: statistics.h2 } for (var j = 0; j <= 23; j++) { arbitrageStatistics[statistics.symbolName].h.push(0) arbitrageStatistics[statistics.symbolName].h2.push(0) } } } else { for (var i in reservedZone.arbitrageStatistics.statistics) { var statistics = reservedZone.arbitrageStatistics.statistics[i] arbitrageStatistics[statistics.symbolName] = { h: statistics.h, h2: statistics.h2, ph: statistics.ph, ph2: statistics.ph2 } } } } } } window.saveArbitrageStatistics = function (arbitrageStatistics) { var reservedZone = {} if (typeof localStorage.reservedZone != "undefined") { reservedZone = JSON.parse(localStorage.reservedZone) } reservedZone.arbitrageStatistics = { latestSaveTime: new Date().getTime(), statistics: [] } for (var i in arbitrageStatistics) { reservedZone.arbitrageStatistics.statistics.push({ symbolName: i, h: arbitrageStatistics[i].h, h2: arbitrageStatistics[i].h2, ph: arbitrageStatistics[i].ph, ph2: arbitrageStatistics[i].ph2 }) } localStorage.reservedZone = JSON.stringify(reservedZone) } window.countArbitrage = function (symbolName, hour) { window.arbitrageStatistics[symbolName].h[hour]++ } window.countArbitrage2 = function (symbolName, hour) { window.arbitrageStatistics[symbolName].h2[hour]++ } } if (typeof $("#arbitrage_dashboard").html() != "undefined") { $("#arbitrage_dashboard").remove() } var arbitrageChartPanel = '' + data + '
' } else { return '' + data + '
' } } }, {title: "Oanda-FIX", render: function (data, type, row) { if (data > 0) { return '' + data + '
' } else { return '' + data + '
' } } }, {title: "Oanda"}, {title: "Op"} ], headerCallback: function (thead, data, start, end, display) { $(thead).css("background-color", window.arbitrageBgColor) }, rowCallback: function (row, data, index) { $("td", row).css("background-color", window.arbitrageBgColor) }, ordering: false, searching: false, bPaginate: false, bLengthChange: false, bFilter: false, bInfo: false, scrollY: "50vh", scrollCollapse: true, paging: false, columnDefs: [ {width: "20%", targets: 0, className: "dt-body-center"}, {width: "20%", targets: 1, className: "dt-body-right"}, {width: "20%", targets: 2, className: "dt-body-right"}, {width: "20%", targets: 3, className: "dt-body-right"}, {width: "20%", targets: 4, className: "dt-body-center"}, {width: "20%", targets: [0], className: "dt-head-center"}, {width: "20%", targets: [1], className: "dt-head-center"}, {width: "20%", targets: [2], className: "dt-head-center"}, {width: "20%", targets: [3], className: "dt-head-center"}, {width: "20%", targets: [4], className: "dt-head-center"}, { targets: -1, data: null, defaultContent: '' + '' + '' } ] }) for (var i in window.oandaApiLoader.oandaQuotes) { $("#arbitrage_prices").DataTable().row.add([ i, "", "", "", "" ]).draw(false) } $("#arbitrage_prices tbody").on("click", "[id*=btn_check_arbitrage]", function () { if (typeof window.arbitragePricesTable != "undefined") { var data = window.arbitragePricesTable.row($(this).parents("tr")).data() if (typeof data == "undefined") { data = window.arbitragePricesTable.row($(this)).data() } window.currentChartSymbolName = data[0] window.arbitrageChart.data.datasets[0].label = window.currentChartSymbolName + "(F-O)" window.arbitrageChart.data.datasets[1].label = window.currentChartSymbolName + "(O-F)" window.arbitrageChart.data.datasets[2].label = window.currentChartSymbolName + "(F-O)" window.arbitrageChart.data.datasets[3].label = window.currentChartSymbolName + "(O-F)" window.updateArbitrageChart(data[0], true, -1) window.updateArbitrageChart2(data[0], true, -1) } }) $("#btn_load_arbitrage_statistics").on("click", function () { window.loadArbitrageStatistics(window.arbitrageStatistics) }) $("#btn_save_arbitrage_statistics").on("click", function () { window.saveArbitrageStatistics(window.arbitrageStatistics) }) } if (window.autoLoadArbitrageStats) { window.loadArbitrageStatistics(window.arbitrageStatistics) } if (typeof window.initArbitrageChart != "undefined") { window.initArbitrageChart(window.arbitrageStatistics) } else { var script = document.createElement("script") document.body.appendChild(script) script.onload = function () { window.initArbitrageChart = function (arbitrageStatistics) { var ctx = document.getElementById("arbitrage_chart").getContext("2d") window.currentChartSymbolName = "EUR/USD" var statistics = arbitrageStatistics[window.currentChartSymbolName] var labels = [] var data = [] var data2 = [] var pdata = [] var pdata2 = [] for (var i = 0; i <= 23; i++) { labels.push(i + "") data.push(statistics.h[i]) data2.push(statistics.h2[i]) pdata.push(statistics.ph[i]) pdata2.push(statistics.ph2[i]) } window.arbitrageChart = new Chart(ctx, { type: "line", data: { labels: labels, datasets: [{ label: window.currentChartSymbolName + "(F-O)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#DB2828", data: data }, { label: window.currentChartSymbolName + "(O-F)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#21BA45", data: data2 }, { label: window.currentChartSymbolName + "(F-O)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#DB2828", borderDash: [2, 3], data: pdata }, { label: window.currentChartSymbolName + "(O-F)", backgroundColor: "rgba(255,255,255,0)", borderColor: "#21BA45", borderDash: [2, 3], data: pdata2 }] }, options: { responsive: true, maintainAspectRatio: false } }) } window.updateArbitrageChart = function (symbolName, bAll, hour) { if (bAll) { for (var i = 0; i <= 23; i++) { window.arbitrageChart.data.datasets[0].data[i] = window.arbitrageStatistics[symbolName].h[i] window.arbitrageChart.data.datasets[2].data[i] = window.arbitrageStatistics[symbolName].ph[i] } } else { window.arbitrageChart.data.datasets[0].data[hour] = window.arbitrageStatistics[symbolName].h[hour] } window.arbitrageChart.update() } window.updateArbitrageChart2 = function (symbolName, bAll, hour) { if (bAll) { for (var i = 0; i <= 23; i++) { window.arbitrageChart.data.datasets[1].data[i] = window.arbitrageStatistics[symbolName].h2[i] window.arbitrageChart.data.datasets[3].data[i] = window.arbitrageStatistics[symbolName].ph2[i] } } else { window.arbitrageChart.data.datasets[1].data[hour] = window.arbitrageStatistics[symbolName].h2[hour] } window.arbitrageChart.update() } window.updatePrevArbitrage = function () { for (var i in window.arbitrageStatistics) { window.arbitrageStatistics[i].ph = window.arbitrageStatistics[i].h window.arbitrageStatistics[i].ph2 = window.arbitrageStatistics[i].h2 window.arbitrageStatistics[i].h = [] window.arbitrageStatistics[i].h2 = [] for (var j = 0; j <= 23; j++) { window.arbitrageStatistics[i].h.push(0) window.arbitrageStatistics[i].h2.push(0) } } } window.initArbitrageChart(window.arbitrageStatistics) } script.onerror = function () { alert("Failed to load required libs. Please refresh this page again.") } script.async = true script.src = "https://cdn.jsdelivr.net/npm/chart.js@2.8.0" } window.arbitrageNotification = "" } else { throw new Error("You need to run fintechee_oanda_loader(you can find it in our Github repo -- Plugin-for-Data-API) first. If you have run the loader, please be patient with the loading time.") } }, function (context) { // Deinit() embedHtml("", 2) for (var i in window.chartIds) { moveLayout(window.chartIds[i], 2) } }, function (context) { // OnTick() if (typeof window.oandaLoaded != "undefined" && window.oandaLoaded) { if (typeof window.latestFIXTickTime == "undefined" || typeof window.latestOandaTickTime == "undefined") return var currTime = new Date().getTime() var hour = new Date(currTime).getHours() var day = new Date(currTime).getDay() if (currTime - window.latestOandaTickTime > 30000) { window.oandaApiLoader.resetupSocket() window.oandaLoaded = false return } if (window.autoSaveArbitrageStats && currTime - window.latestSaveTime > 60000) { window.saveArbitrageStatistics(window.arbitrageStatistics) window.latestSaveTime = currTime } window.latestFIXTickTime = currTime var account = getAccount(context, 0) var brokerName = getBrokerNameOfAccount(account) var accountId = getAccountIdOfAccount(account) var currentTick = getCurrentTick(context) var symbolName = currentTick.symbolName var askFIXAPI = currentTick.ask var bidFIXAPI = currentTick.bid if (window.latestDay != day) { window.updatePrevArbitrage() window.updateArbitrageChart(symbolName, true, -1) window.updateArbitrageChart2(symbolName, true, -1) window.latestDay = day } if (window.oandaApiLoader.oandaQuotes[symbolName] == null) return var askOanda = window.oandaApiLoader.oandaQuotes[symbolName].ask var bidOanda = window.oandaApiLoader.oandaQuotes[symbolName].bid if (askFIXAPI != null && bidFIXAPI != null && askOanda != null && bidOanda != null) { var table = $('#arbitrage_prices').DataTable() var tb = $('#arbitrage_prices').dataTable() table.columns().eq(0).each(function (index) { if (index == 0) { var column = table.column(index).data() for (var i in column) { if (isNaN(i)) continue var rowId = parseInt(i) if (column[i] == symbolName) { tb.fnUpdate(Math.round((bidOanda - askFIXAPI) * 100000) / 100000, rowId, 1, false, false) tb.fnUpdate(Math.round((bidFIXAPI - askOanda) * 100000) / 100000, rowId, 2, false, false) tb.fnUpdate(Math.round((askOanda + bidOanda) / 2 * 100000) / 100000, rowId, 3, false, false) break } } } }) if (bidOanda > askFIXAPI) { window.countArbitrage(symbolName, hour) if (symbolName == window.currentChartSymbolName) { window.updateArbitrageChart(symbolName, false, hour) } // var msg = new Date() + " " + symbolName + " Chance!! Oanda Bid: " + bidOanda + ", FIXAPI Ask: " + askFIXAPI + ", Difference: " + (bidOanda - askFIXAPI) + "\n" // printMessage(msg) } if (bidFIXAPI > askOanda) { window.countArbitrage2(symbolName, hour) if (symbolName == window.currentChartSymbolName) { window.updateArbitrageChart2(symbolName, false, hour) } // var msg = new Date() + " " + symbolName + " Chance!! FIXAPI Bid: " + bidFIXAPI + ", Oanda Ask: " + askOanda + ", Difference: " + (bidFIXAPI - askOanda) + "\n" // printMessage(msg) } } } } ) ================================================ FILE: EA/Plugin-for-Deribit/plugin_for_deribit.js ================================================ registerEA( "plugin_for_deribit", "A plugin to trade cryptocurrency options(v0.08)", [{ name: "interval", value: 30, required: true, type: "Integer", range: null, step: null }], function (context) { // Init() var orderBookId = null var loaded = false var latestHb = null var interval = getEAParameter(context, "interval") * 1000 function convertOptionName (rawName) { var name = rawName.split("-") var year = name[1].substring(5, 7) var mon = name[1].substring(2, 5) var dt = name[1].substring(0, 2) var month = "00" if (mon == "JAN") { month = "01" } else if (mon == "FEB") { month = "02" } else if (mon == "MAR") { month = "03" } else if (mon == "APR") { month = "04" } else if (mon == "MAY") { month = "05" } else if (mon == "JUN") { month = "06" } else if (mon == "JUL") { month = "07" } else if (mon == "AUG") { month = "08" } else if (mon == "SEP") { month = "09" } else if (mon == "OCT") { month = "10" } else if (mon == "NOV") { month = "11" } else if (mon == "DEC") { month = "12" } var expiration = parseInt(year + month + dt) var optionName2 = name[0] + "-" + dt + mon + year return { optionName: name[0] + "-" + expiration, optionName2: optionName2, instrument: name[0], expiration: expiration, year: year, month: month, dt: dt, strikePrice: parseFloat(name[2]), callOrPut: name[3] } } function parseOrderBook (data) { var orderBookData = [] for (var i in data) { var optionName = convertOptionName(data[i].instrument_name) if (typeof orderBookData[optionName.optionName] == "undefined") { orderBookData[optionName.optionName] = { optionName: optionName.optionName, optionName2: optionName.optionName2, instrument: optionName.instrument, expiration: optionName.expiration, year: optionName.year, month: optionName.month, dt: optionName.dt, prices: [], arrPrices: [] } } if (typeof orderBookData[optionName.optionName].prices[optionName.strikePrice] == "undefined") { orderBookData[optionName.optionName].prices[optionName.strikePrice] = { strikePrice: optionName.strikePrice, bidC: optionName.callOrPut == "C" ? data[i].bid_price : null, askC: optionName.callOrPut == "C" ? data[i].ask_price : null, bidP: optionName.callOrPut == "P" ? data[i].bid_price : null, askP: optionName.callOrPut == "P" ? data[i].ask_price : null } } else { var price = orderBookData[optionName.optionName].prices[optionName.strikePrice] if (price.bidC == null) { price.bidC = optionName.callOrPut == "C" ? data[i].bid_price : null } if (price.askC == null) { price.askC = optionName.callOrPut == "C" ? data[i].ask_price : null } if (price.bidP == null) { price.bidP = optionName.callOrPut == "P" ? data[i].bid_price : null } if (price.askP == null) { price.askP = optionName.callOrPut == "P" ? data[i].ask_price : null } } } for (var i in orderBookData) { for (var j in orderBookData[i].prices) { orderBookData[i].arrPrices.push(orderBookData[i].prices[j]) } } var expirations = [] for (var i in orderBookData) { expirations.push({ expiration: orderBookData[i].expiration, optionName: orderBookData[i].optionName, optionName2: orderBookData[i].optionName2 }) } expirations.sort(function (a, b) {return a.expiration - b.expiration}) return { expirations: expirations, orderBookData: orderBookData } } function showOptions (expirations) { var optionsHtml = "" for (var i in expirations) { optionsHtml += '' + data + '
' } else if (row[5] > 0) { return '' + data + '
' } else { return '' + data + '
' } } }, {title: "Ask(C)", render: function (data, type, row) { if (row[6] == 0) { return '' + data + '
' } else if (row[6] > 0) { return '' + data + '
' } else { return '' + data + '
' } } }, {title: "Strike Price"}, {title: "Bid(P)", render: function (data, type, row) { if (row[7] == 0) { return '' + data + '
' } else if (row[7] > 0) { return '' + data + '
' } else { return '' + data + '
' } } }, {title: "Ask(P)", render: function (data, type, row) { if (row[8] == 0) { return '' + data + '
' } else if (row[8] > 0) { return '' + data + '
' } else { return '' + data + '
' } } }, {title: "Diff(BC)"}, {title: "Diff(AC)"}, {title: "Diff(BP)"}, {title: "Diff(AP)"} ], ordering: false, searching: false, bPaginate: false, bLengthChange: false, bFilter: false, bInfo: false, scrollY: '50vh', scrollCollapse: true, paging: false, columnDefs: [ {width: "20%", targets: 0, className: "dt-body-right"}, {width: "20%", targets: 1, className: "dt-body-right"}, {width: "20%", targets: 2, className: "dt-body-center"}, {width: "20%", targets: 3, className: "dt-body-right"}, {width: "20%", targets: 4, className: "dt-body-right"}, {width: "20%", targets: [0, 1, 2, 3, 4], className: "dt-head-center"}, {targets: [5, 6, 7, 8], visible: false} ] }) } $("#get_btc").on("click", function () { getOrderBook("BTC") }) $("#get_eth").on("click", function () { getOrderBook("ETH") }) $("#disconnect_ws").on("click", function () { disconnectCryptoOptionsWS() }) initCryptoOptionsWS() $("#crypto_options_dashboard").modal("show") if (typeof window.wsTimer != "undefined") { clearInterval(window.wsTimer) } window.wsTimer = setInterval(function () { checkHb() }, interval) }, function (context) { // Deinit() }, function (context) { // OnTick() }) ================================================ FILE: EA/Plugin-for-Deribit/usage.txt ================================================ You can use this EA to get crypto options' streaming quotes. Crypto options are much more complex than Forex or CFD. So, this plugin is for reference only. ================================================ FILE: EA/Plugin-for-EOS/decentralized_exchange_eos_approve.js ================================================ registerEA( "decentralized_exchange_eos_approve", "A decentralized exchange plugin to approve a proposal for exchanging digital assets via EOS platform(v1.0)", [{ // parameters name: "proposalName", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "proposer", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "approver", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var proposalName = getEAParameter(context, "proposalName") var proposer = getEAParameter(context, "proposer") var approver = getEAParameter(context, "approver") if (proposalName == null || proposalName == "") { popupErrorMessage("The proposal name should not be empty.") return } if (proposer == null || proposer == "") { popupErrorMessage("The proposer should not be empty.") return } if (approver == null || approver == "") { popupErrorMessage("The approver should not be empty.") return } (async () => { try { const result = await window.eos_api.transact({ actions: [{ account: "eosio.msig", name: "approve", authorization: [{ actor: approver, permission: "active" }], data: { proposer: proposer, proposal_name: proposalName, level: { actor: approver, permission: "active", } } }] }, { blocksBehind: 3, expireSeconds: 30, broadcast: true, sign: true }) popupMessage("Approved!\n\n" + JSON.stringify(result, null, 2)) } catch (e) { popupErrorMessage("Caught exception: " + e) if (e instanceof window.eosjs_jsonrpc.RpcError) { popupErrorMessage(JSON.stringify(e.json, null, 2)) } } })() }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/decentralized_exchange_eos_cancel.js ================================================ registerEA( "decentralized_exchange_eos_cancel", "A decentralized exchange plugin to cancel a proposal for exchanging digital assets via EOS platform(v1.0)", [{ // parameters name: "proposalName", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "proposer", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "canceler", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var proposalName = getEAParameter(context, "proposalName") var proposer = getEAParameter(context, "proposer") var canceler = getEAParameter(context, "canceler") if (proposalName == null || proposalName == "") { popupErrorMessage("The proposal name should not be empty.") return } if (proposer == null || proposer == "") { popupErrorMessage("The proposer should not be empty.") return } if (canceler == null || canceler == "") { popupErrorMessage("The canceler should not be empty.") return } (async () => { try { const result = await window.eos_api.transact({ actions: [{ account: "eosio.msig", name: "cancel", authorization: [{ actor: canceler, permission: "active" }], data: { proposer: proposer, proposal_name: proposalName, canceler: canceler } }] }, { blocksBehind: 3, expireSeconds: 30, broadcast: true, sign: true }) popupMessage("Canceled!\n\n" + JSON.stringify(result, null, 2)) } catch (e) { popupErrorMessage("Caught exception: " + e) if (e instanceof window.eosjs_jsonrpc.RpcError) { popupErrorMessage(JSON.stringify(e.json, null, 2)) } } })() }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/decentralized_exchange_eos_exec.js ================================================ registerEA( "decentralized_exchange_eos_exec", "A decentralized exchange plugin to execute a transaction of exchanging digital assets via EOS platform(v1.0)", [{ // parameters name: "proposalName", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "proposer", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "executor", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var proposalName = getEAParameter(context, "proposalName") var proposer = getEAParameter(context, "proposer") var executor = getEAParameter(context, "executor") if (proposalName == null || proposalName == "") { popupErrorMessage("The proposal name should not be empty.") return } if (proposer == null || proposer == "") { popupErrorMessage("The proposer should not be empty.") return } if (executor == null || executor == "") { popupErrorMessage("The executor should not be empty.") return } (async () => { try { const result = await window.eos_api.transact({ actions: [{ account: "eosio.msig", name: "exec", authorization: [{ actor: executor, permission: "active" }], data: { proposer: proposer, proposal_name: proposalName, executer: executor } }] }, { blocksBehind: 3, expireSeconds: 30, broadcast: true, sign: true }) popupMessage("Transaction pushed!\n\n" + JSON.stringify(result, null, 2)) } catch (e) { popupErrorMessage("Caught exception: " + e) if (e instanceof window.eosjs_jsonrpc.RpcError) { popupErrorMessage(JSON.stringify(e.json, null, 2)) } } })() }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/decentralized_exchange_eos_propose.js ================================================ registerEA( "decentralized_exchange_eos_propose", "A decentralized exchange plugin to propose for exchanging digital assets via EOS platform(v1.01)", [{ // parameters name: "proposalName", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "asset", value: "eosio.token", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "proposer", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "exchange", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "escrow", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "amount", value: 0, required: true, type: PARAMETER_TYPE.INTEGER, range: [0, null] }, { name: "currency", value: "SYS", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "memo", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var proposalName = getEAParameter(context, "proposalName") var asset = getEAParameter(context, "asset") var proposer = getEAParameter(context, "proposer") var exchange = getEAParameter(context, "exchange") var escrow = getEAParameter(context, "escrow") var amount = getEAParameter(context, "amount") var currency = getEAParameter(context, "currency") var memo = getEAParameter(context, "memo") if (proposalName == null || proposalName == "") { popupErrorMessage("The proposal name should not be empty.") return } if (proposer == null || proposer == "") { popupErrorMessage("The proposer should not be empty.") return } if (exchange == null || exchange == "") { popupErrorMessage("The exchange should not be empty.") return } if (escrow == null || escrow == "") { popupErrorMessage("The escrow account should not be empty.") return } if (amount <= 0) { popupErrorMessage("The amount should be greater than zero.") return } if (memo == null) { memo = "" } const actions = [{ account: asset, name: "transfer", authorization: [{ actor: escrow, permission: "active", }], data: { from: escrow, to: exchange, quantity: Math.floor(amount) + ".0000 " + currency, memo: memo } }]; (async () => { try { const serialized_actions = await window.eos_api.serializeActions(actions) const proposeInput = { proposer: proposer, proposal_name: proposalName, // We make the threshold be 1(not 2) to simplify the process, because multi-sig requires that all approvers are online, which is not that realistic. requested: [{ actor: exchange, permission: "active" }], trx: { expiration: new Date(new Date().getTime() + 3600000).toISOString().slice(0,19), ref_block_num: 0, ref_block_prefix: 0, max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [], actions: serialized_actions, transaction_extensions: [] } } const result = await window.eos_api.transact({ actions: [{ account: "eosio.msig", name: "propose", authorization: [{ actor: proposer, permission: "active" }], data: proposeInput }] }, { blocksBehind: 3, expireSeconds: 30, broadcast: true, sign: true }) popupMessage("Proposed!\n\n" + JSON.stringify(result, null, 2)) } catch (e) { popupErrorMessage("Caught exception: " + e) if (e instanceof window.eosjs_jsonrpc.RpcError) { popupErrorMessage(JSON.stringify(e.json, null, 2)) } } })() }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/decentralized_exchange_eos_unapprove.js ================================================ registerEA( "decentralized_exchange_eos_unapprove", "A decentralized exchange plugin to unapprove a proposal for exchanging digital assets via EOS platform(v1.0)", [{ // parameters name: "proposalName", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "proposer", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "actor", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var proposalName = getEAParameter(context, "proposalName") var proposer = getEAParameter(context, "proposer") var actor = getEAParameter(context, "actor") if (proposalName == null || proposalName == "") { popupErrorMessage("The proposal name should not be empty.") return } if (proposer == null || proposer == "") { popupErrorMessage("The proposer should not be empty.") return } if (actor == null || actor == "") { popupErrorMessage("The actor should not be empty.") return } (async () => { try { const result = await window.eos_api.transact({ actions: [{ account: "eosio.msig", name: "unapprove", authorization: [{ actor: actor, permission: "active" }], data: { proposer: proposer, proposal_name: proposalName, level: { actor: actor, permission: "active", } } }] }, { blocksBehind: 3, expireSeconds: 30, broadcast: true, sign: true }) popupMessage("Unapproved!\n\n" + JSON.stringify(result, null, 2)) } catch (e) { popupErrorMessage("Caught exception: " + e) if (e instanceof window.eosjs_jsonrpc.RpcError) { popupErrorMessage(JSON.stringify(e.json, null, 2)) } } })() }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/payment_gateway_eos.js ================================================ registerEA( "payment_gateway_eos", "A payment gateway plugin to make you fund(deposit or withdraw) via EOS platform(v1.03)", [{ // parameters name: "asset", value: "eosio.token", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "from", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "to", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "amount", value: 0, required: true, type: PARAMETER_TYPE.INTEGER, range: [0, null] }, { name: "currency", value: "SYS", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "memo", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var asset = getEAParameter(context, "asset") var from = getEAParameter(context, "from") var to = getEAParameter(context, "to") var amount = getEAParameter(context, "amount") var currency = getEAParameter(context, "currency") var memo = getEAParameter(context, "memo") if (from == null || from == "") { popupErrorMessage("The sender should not be empty.") return } if (to == null || to == "") { popupErrorMessage("The recipient should not be empty.") return } if (amount <= 0) { popupErrorMessage("The amount should be greater than zero.") return } if (memo == null) { memo = "" } (async () => { try { const result = await window.eos_api.transact({ actions: [{ account: asset, name: "transfer", authorization: [{ actor: from, permission: "active", }], data: { from: from, to: to, quantity: Math.floor(amount) + ".0000 " + currency, memo: memo } }] }, { blocksBehind: 3, expireSeconds: 30 }) popupMessage("Transaction pushed!\n\n" + JSON.stringify(result, null, 2)) } catch (e) { popupErrorMessage("Caught exception: " + e) if (e instanceof window.eosjs_jsonrpc.RpcError) { popupErrorMessage(JSON.stringify(e.json, null, 2)) } } })() }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/payment_gateway_eos_lib_loader.js ================================================ registerEA( "payment_gateway_eos_lib_loader", "A payment gateway plugin to load EOS libraries(v1.01)", [{ // parameters name: "privateKey", value: "", required: false, type: PARAMETER_TYPE.STRING, range: null }, { name: "jsonRpcUrl", value: "https://nodes.get-scatter.com", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "jssig", value: "https://www.fintechee.com/js/eos/eosjs-jssig.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "jsonrpc", value: "https://www.fintechee.com/js/eos/eosjs-jsonrpc.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "api", value: "https://www.fintechee.com/js/eos/eosjs-api.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var defaultPrivateKey = getEAParameter(context, "privateKey") var jsonRpcUrl = getEAParameter(context, "jsonRpcUrl") var jssig = getEAParameter(context, "jssig") var jsonrpc = getEAParameter(context, "jsonrpc") var api = getEAParameter(context, "api") if (defaultPrivateKey == null || defaultPrivateKey == "") { popupErrorMessage("The private key should not be empty.") return } var tags = document.getElementsByTagName("script") for (var i = tags.length - 1; i >= 0; i--) { if (tags[i] && tags[i].getAttribute("src") != null && (tags[i].getAttribute("src") == jssig || tags[i].getAttribute("src") == jsonrpc || tags[i].getAttribute("src") == api)) { tags[i].parentNode.removeChild(tags[i]) } } var script1 = document.createElement("script") document.body.appendChild(script1) script1.onload = function () { var script2 = document.createElement("script") document.body.appendChild(script2) script2.onload = function () { var script3 = document.createElement("script") document.body.appendChild(script3) script3.onload = function () { window.eosjs_jsonrpc = eosjs_jsonrpc var eos_rpc = new eosjs_jsonrpc.JsonRpc(jsonRpcUrl) var eos_signatureProvider = new eosjs_jssig.JsSignatureProvider([defaultPrivateKey]) window.eos_api = new eosjs_api.Api({rpc: eos_rpc, signatureProvider: eos_signatureProvider}) } script3.onerror = function () {} script3.async = true script3.src = jssig } script2.onerror = function () {} script2.async = true script2.src = jsonrpc } script1.onerror = function () {} script1.async = true script1.src = api }, function (context) { // Deinit() }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/payment_gateway_eos_scatter.js ================================================ registerEA( "payment_gateway_eos_scatter", "A payment gateway plugin to load the libraries of EOS and Scatter(v1.0)", [{ // parameters name: "jsonRpcUrl", value: "https://nodes.get-scatter.com", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "chainId", value: "aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "scatterCore", value: "https://www.fintechee.com/js/eos/scatterjs-core.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "scatterEos", value: "https://www.fintechee.com/js/eos/scatterjs-plugin-eosjs2.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "jsonrpc", value: "https://www.fintechee.com/js/eos/eosjs-jsonrpc.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }, { name: "api", value: "https://www.fintechee.com/js/eos/eosjs-api.min.js", required: true, type: PARAMETER_TYPE.STRING, range: null }], function (context) { // Init() var jsonRpcUrl = getEAParameter(context, "jsonRpcUrl") var chainId = getEAParameter(context, "chainId") var scatterCore = getEAParameter(context, "scatterCore") var scatterEos = getEAParameter(context, "scatterEos") var jsonrpc = getEAParameter(context, "jsonrpc") var api = getEAParameter(context, "api") var tags = document.getElementsByTagName("script") for (var i = tags.length - 1; i >= 0; i--) { if (tags[i] && tags[i].getAttribute("src") != null && (tags[i].getAttribute("src") == scatterCore || tags[i].getAttribute("src") == scatterEos || tags[i].getAttribute("src") == jsonrpc || tags[i].getAttribute("src") == api)) { tags[i].parentNode.removeChild(tags[i]) } } var script1 = document.createElement("script") document.body.appendChild(script1) script1.onload = function () { var script2 = document.createElement("script") document.body.appendChild(script2) script2.onload = function () { var script3 = document.createElement("script") document.body.appendChild(script3) script3.onload = function () { var script4 = document.createElement("script") document.body.appendChild(script4) script4.onload = function () { var parsedJsonRpcUrl = jsonRpcUrl.split("://") var parsedJsonRpcUrl2 = parsedJsonRpcUrl[1].split(":") const network = ScatterJS.Network.fromJson({ blockchain: "eos", protocol: parsedJsonRpcUrl[0], host: parsedJsonRpcUrl2[0], port: parsedJsonRpcUrl2.length == 1 ? 443 : parseInt(parsedJsonRpcUrl2[1]), chainId: chainId }) ScatterJS.plugins(new ScatterEOS()) ScatterJS.scatter.connect("www.fintechee.com", {network}).then(function (connected) { if(!connected) { popupErrorMessage("Failed to connect to your Scatter APP.") return false } const scatter = ScatterJS.scatter window.eosjs_jsonrpc = eosjs_jsonrpc var eos_rpc = new eosjs_jsonrpc.JsonRpc(jsonRpcUrl) window.eos_api = scatter.eos(network, eosjs_api.Api, {rpc: eos_rpc}); (async function () { if (scatter.identity) { scatter.logout() } await scatter.login() window.scatter = scatter popupMessage("Connected to Scatter successfully!") })() window.ScatterJS = null }) } script4.onerror = function () {} script4.async = true script4.src = scatterEos } script3.onerror = function () {} script3.async = true script3.src = scatterCore } script2.onerror = function () {} script2.async = true script2.src = jsonrpc } script1.onerror = function () {} script1.async = true script1.src = api }, function (context) { // Deinit() window.scatter.logout() window.scatter = null }, function (context) { // OnTick() } ) ================================================ FILE: EA/Plugin-for-EOS/usage.txt ================================================ This folder contains programs that are used for integrating with the EOS blockchain. These programs provide excellent examples for developers who want to understand how the payment gateway works, and they also demonstrate how to interact with a crypto wallet. Furthermore, it is possible to extend these plugins to support a different blockchain, if needed. ================================================ FILE: EA/Plugin-for-FXCM/README.md ================================================ ## Developing. Will be coming soon. ================================================ FILE: EA/Plugin-for-MQL/README.md ================================================ # Expert-Advisor-Cpp-Compiler This is a Nodejs package to help Fintechee's users compile C/C++/MQL source codes(to make the expert advisors runnable on browser). It will be installed on your local PC. So, network is not required to compile your C/C++/MQL source files. To know more details about Fintechee, please access our official website: https://www.fintechee.com or our main Github repo: https://github.com/fintechee/Expert-Advisor-Studio   ## Prerequisite Emscripten is required to compile C/C++/MQL files. So, you need to install it in advance. https://emscripten.org/docs/getting_started/downloads.html#installation-instructions ## Usage 1. Installation Please access this repo: https://github.com/fintechees/Expert-Advisor-Cpp-Compiler - Download the git repo, and then extract the zip file. - cd the directory - npm i 2. Run - node app.js - Access https://www.fintechee.com/web-trader/ - Click the "Console" on the menubar(on the left of the page). - Choose "C/C++" tab on the panel. - Open your C/C++ file and then click "Generate Indicator" or "Generate EA". C/C++ source codes and a JSON string will be generated. You can modify your original source codes by the generated codes. The generated parts are used to define the meta information of your program, such as the variables and data output and can be helpful to make your original codes compilable. - Click "Compile Indicator" or "Compile EA" after you finish modifying your original codes. - Use plugin_for_mql to load the output js(and WebAssembly) that is generated by the "Compile" step. The generated JSON string will be used as the parameter of the plugins. Please access this page to know more details: https://www.fintechee.com/compatible-with-mql/ The tool in the page: https://www.fintechee.com/compatible-with-mql/ is an alternative generator to the "Generate Indicator" or "Generate EA" function. 3. Output files - The output files(js and WebAssembly) will be stored in the sub-directory: ./static - you can access ./static via http://127.0.0.1:3000/js/[your_output_js_file_name] (/js refers to ./static) ## Tutorials The tutorials will be coming soon. ## License MIT ================================================ FILE: EA/Plugin-for-MQL/mqlea2fintechee.h ================================================ #include