2023-08-01 05:04:27 +00:00
|
|
|
import "./tracing.js"
|
2023-07-25 23:50:28 +00:00
|
|
|
import express from "express";
|
|
|
|
|
import cors from "cors";
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
import fetch from "node-fetch";
|
|
|
|
|
const app = express();
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
import pg from "pg";
|
2023-07-28 11:16:12 +00:00
|
|
|
|
|
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
const client = new pg.Client(
|
|
|
|
|
"postgresql://crate@crate1.home.neb:5432/oversite"
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
client.connect();
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-08-03 10:29:49 +00:00
|
|
|
//var ASKGAP = 0.9955;
|
|
|
|
|
//var BIDGAP = 1.0045;
|
2023-08-07 14:45:39 +00:00
|
|
|
var ASKGAP = 0.0008;
|
|
|
|
|
var BIDGAP = 0.0008;
|
|
|
|
|
|
|
|
|
|
var NTP = 0.0004;
|
2023-08-03 10:12:29 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
const port = 3000;
|
|
|
|
|
const host = "0.0.0.0";
|
2023-07-25 18:42:23 +00:00
|
|
|
|
|
|
|
|
const STATE = {};
|
2023-07-28 11:16:12 +00:00
|
|
|
|
2023-07-25 18:42:23 +00:00
|
|
|
const PRICES = {};
|
|
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
import axios from "axios";
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
const APIURL = "https://api-fxpractice.oanda.com/v3";
|
2023-07-28 11:16:12 +00:00
|
|
|
const STREAMURL = "https://stream-fxpractice.oanda.com/v3";
|
|
|
|
|
const APIURL_DEMO = "https://api-fxpractice.oanda.com/v3";
|
|
|
|
|
const STREAMURL_DEMO = "https://stream-fxpractice.oanda.com/v3";
|
|
|
|
|
|
2023-07-25 18:42:23 +00:00
|
|
|
const accounts = {
|
2023-07-25 23:50:28 +00:00
|
|
|
"1": {
|
|
|
|
|
ACCT: "101-001-8005237-001",
|
|
|
|
|
APIKEY: "e88218d201bd344c2dc3c469f8f8d1f3-e77504680a17f51f0baecf9dababa40b",
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
"4": {
|
|
|
|
|
ACCT: "101-001-8005237-002",
|
|
|
|
|
APIKEY: "e88218d201bd344c2dc3c469f8f8d1f3-e77504680a17f51f0baecf9dababa40b",
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
"2": {
|
|
|
|
|
APIKEY: "b954456a3f4ac735de2555e1af50abf7-ed83ace2f9fb86412b76608daefc73a5",
|
|
|
|
|
ACCT: "101-001-23367262-002",
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
"3": {
|
|
|
|
|
APIKEY: "d4ea6095fe8017841279416437520aee-fa23a0556fb501520ceedbff5f405267",
|
|
|
|
|
ACCT: "101-002-26241098-001",
|
|
|
|
|
},
|
|
|
|
|
};
|
2023-07-25 18:42:23 +00:00
|
|
|
|
|
|
|
|
function processTP() {
|
2023-07-28 11:16:12 +00:00
|
|
|
try {
|
|
|
|
|
for (const pair in PRICES) {
|
|
|
|
|
for (const acct in STATE) {
|
|
|
|
|
|
2023-08-03 10:29:49 +00:00
|
|
|
if (typeof(STATE[acct][pair]) !== 'undefined' && STATE[acct][pair]["watch"] == "ask") {
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[acct][pair]["currentPrice"] = PRICES[pair]["ask"];
|
2023-08-08 08:43:37 +00:00
|
|
|
STATE[acct][pair]["delta"] = PRICES[pair]["ask"] - STATE[acct][pair]["base"];
|
|
|
|
|
|
|
|
|
|
if (pair.includes("JPY")) {
|
|
|
|
|
STATE[acct][pair]["delta"] = STATE[acct][pair]["delta"] * 100;
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
STATE[acct][pair]["delta"] = STATE[acct][pair]["delta"] * 10000;
|
|
|
|
|
}
|
2023-08-07 14:45:39 +00:00
|
|
|
if (STATE[acct][pair]["TP"] == true) {
|
|
|
|
|
STATE[acct][pair]["TPVal"] = STATE[acct][pair]["NTPVal"];
|
|
|
|
|
}
|
|
|
|
|
let newtrigger = PRICES[pair]["ask"] - STATE[acct][pair]["TPVal"]
|
|
|
|
|
|
|
|
|
|
if (STATE[acct][pair]["trigger"] < newtrigger) {
|
|
|
|
|
STATE[acct][pair]["trigger"] = newtrigger;
|
|
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
|
2023-08-07 14:45:39 +00:00
|
|
|
|
|
|
|
|
if (
|
2023-08-03 10:12:29 +00:00
|
|
|
PRICES[pair]["ask"] < STATE[acct][pair]["trigger"]
|
2023-07-28 11:16:12 +00:00
|
|
|
) {
|
|
|
|
|
closeOrder(
|
|
|
|
|
accounts[acct]["ACCT"],
|
|
|
|
|
accounts[acct]["APIKEY"],
|
|
|
|
|
STATE[acct][pair]["trade_id"]
|
|
|
|
|
);
|
|
|
|
|
delete STATE[acct][pair];
|
|
|
|
|
}
|
2023-08-07 14:45:39 +00:00
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
if (STATE[acct][pair]["base"] + STATE[acct][pair]["TPVal"] <= PRICES[pair]["ask"]) {
|
2023-07-28 11:16:12 +00:00
|
|
|
STATE[acct][pair]["TP"] = true;
|
2023-08-07 14:45:39 +00:00
|
|
|
}
|
|
|
|
|
} catch(error) {
|
|
|
|
|
console.log(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (typeof(STATE[acct][pair]) !== 'undefined' && STATE[acct][pair]["watch"] == "bid") {
|
|
|
|
|
STATE[acct][pair]["currentPrice"] = PRICES[pair]["bid"];
|
2023-08-08 08:43:37 +00:00
|
|
|
STATE[acct][pair]["delta"] = STATE[acct][pair]["base"] - PRICES[pair]["bid"];
|
|
|
|
|
if (pair.includes("JPY")) {
|
|
|
|
|
STATE[acct][pair]["delta"] = STATE[acct][pair]["delta"] * 100;
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
STATE[acct][pair]["delta"] = STATE[acct][pair]["delta"] * 10000;
|
|
|
|
|
}
|
2023-08-07 14:45:39 +00:00
|
|
|
if (STATE[acct][pair]["TP"] == true) {
|
|
|
|
|
STATE[acct][pair]["TPVal"] = STATE[acct][pair]["NTPVal"];
|
|
|
|
|
}
|
2023-08-08 08:43:37 +00:00
|
|
|
let newtrigger = PRICES[pair]["bid"] + STATE[acct][pair]["TPVal"]
|
2023-08-07 14:45:39 +00:00
|
|
|
if (STATE[acct][pair]["trigger"] > newtrigger) {
|
|
|
|
|
STATE[acct][pair]["trigger"] = newtrigger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (
|
2023-08-03 10:12:29 +00:00
|
|
|
PRICES[pair]["bid"] > STATE[acct][pair]["trigger"]
|
2023-07-28 11:16:12 +00:00
|
|
|
) {
|
|
|
|
|
closeOrder(
|
|
|
|
|
accounts[acct]["ACCT"],
|
|
|
|
|
accounts[acct]["APIKEY"],
|
|
|
|
|
STATE[acct][pair]["trade_id"]
|
|
|
|
|
);
|
|
|
|
|
delete STATE[acct][pair];
|
|
|
|
|
}
|
2023-08-07 14:45:39 +00:00
|
|
|
try {
|
|
|
|
|
if (STATE[acct][pair]["base"] - STATE[acct][pair]["TPVal"] >= PRICES[pair]["bid"]) {
|
|
|
|
|
STATE[acct][pair]["TP"] = true;
|
|
|
|
|
}
|
|
|
|
|
} catch(error) {
|
|
|
|
|
console.log(error);
|
|
|
|
|
}
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
} catch (e) {
|
|
|
|
|
console.log("error prices");
|
|
|
|
|
console.log(e);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-28 11:16:12 +00:00
|
|
|
function saveState() {
|
2023-08-07 14:45:39 +00:00
|
|
|
client.query(`insert into osapi_state (account_state, state_date) values ($1, now())`, [JSON.stringify(STATE) ]);
|
2023-07-28 11:16:12 +00:00
|
|
|
|
2023-07-26 11:27:22 +00:00
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
setInterval(processTP, 1500);
|
2023-08-07 14:45:39 +00:00
|
|
|
setInterval(saveState, 3000);
|
2023-07-28 11:16:12 +00:00
|
|
|
|
2023-07-26 11:27:22 +00:00
|
|
|
|
|
|
|
|
async function loadState() {
|
|
|
|
|
|
2023-08-07 14:45:39 +00:00
|
|
|
let res = await client.query(`select account_state from osapi_state order by state_date desc limit 1`);
|
2023-07-26 11:27:22 +00:00
|
|
|
|
2023-07-28 11:16:12 +00:00
|
|
|
if (res.rows.length !== 0) {
|
2023-08-07 14:45:39 +00:00
|
|
|
var st ;
|
|
|
|
|
console.log(res['rows'][0]['account_state']);
|
|
|
|
|
if (typeof(res['rows'][0]['account_state']) === 'object') {
|
|
|
|
|
st = res['rows'][0]['account_state'];
|
|
|
|
|
} else {
|
|
|
|
|
st = JSON.parse(res['rows'][0]['account_state']);
|
|
|
|
|
}
|
|
|
|
|
for (const k in st) {
|
|
|
|
|
STATE[k] = st[k];
|
2023-08-01 05:04:27 +00:00
|
|
|
}
|
|
|
|
|
console.log(STATE);
|
2023-07-26 11:27:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 18:42:23 +00:00
|
|
|
async function getTransactionsAll(account, acct_id, api_key) {
|
2023-07-28 11:16:12 +00:00
|
|
|
console.log("getTransactionsAll");
|
2023-07-25 18:42:23 +00:00
|
|
|
for (const rg of [...Array(32).keys()]) {
|
|
|
|
|
try {
|
2023-07-25 23:50:28 +00:00
|
|
|
let f = rg * 1000 + 1;
|
|
|
|
|
let to = f + 1000;
|
2023-07-25 18:42:23 +00:00
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/transactions/idrange?from=${f}&to=${to}`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "get",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (const t of response.data.transactions) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let qty = 0;
|
|
|
|
|
let tp = "";
|
|
|
|
|
if (typeof t["instrument"] !== undefined) {
|
|
|
|
|
tp = t["instrument"];
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
if (typeof t["units"] !== undefined) {
|
|
|
|
|
qty = t["units"];
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
await client.query(
|
|
|
|
|
`insert into orders (order_id, account_id, tpair, order_type, order_ref, order_reason, order_date, order_data, quantity) values ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
|
|
|
|
|
[t.id, account, tp, t.type, t.batchID, t.reason, t.time, t, qty]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2023-08-07 14:45:39 +00:00
|
|
|
console.log(error);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async function getTransactions(account, acct_id, api_key) {
|
2023-07-28 11:16:12 +00:00
|
|
|
console.log("getTransactions");
|
2023-08-01 05:04:27 +00:00
|
|
|
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
2023-07-25 23:50:28 +00:00
|
|
|
const res = await client.query(
|
|
|
|
|
`SELECT max(order_id) as order_id from orders where account_id = ${account}`
|
|
|
|
|
);
|
|
|
|
|
let f = res.rows[0].order_id;
|
|
|
|
|
let to = f + 1000;
|
2023-07-25 18:42:23 +00:00
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/transactions/idrange?from=${f}&to=${to}`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "get",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (const t of response.data.transactions) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let qty = 0;
|
|
|
|
|
let tp = "";
|
|
|
|
|
if (typeof t["instrument"] !== undefined) {
|
|
|
|
|
tp = t["instrument"];
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
if (typeof t["units"] !== undefined) {
|
|
|
|
|
qty = t["units"];
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
await client.query(
|
|
|
|
|
`insert into orders (order_id, account_id, tpair, order_type, order_ref, order_reason, order_date, order_data, quantity) values ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
|
|
|
|
|
[t.id, account, tp, t.type, t.batchID, t.reason, t.time, t, qty]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function getTrades(acct_id, api_key) {
|
2023-07-28 11:16:12 +00:00
|
|
|
console.log("getTrades");
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/openTrades`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "get",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async function getTradesByInstrument(acct_id, api_key, instrument) {
|
2023-07-28 11:16:12 +00:00
|
|
|
console.log("getTradesByInstrument");
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/trades?instrument=${instrument}`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "get",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
|
|
|
|
//console.log(response)
|
|
|
|
|
if (response.data.trades.length == 0) {
|
2023-07-25 23:50:28 +00:00
|
|
|
return;
|
2023-07-25 18:42:23 +00:00
|
|
|
} else {
|
2023-07-25 23:50:28 +00:00
|
|
|
return response.data.trades[0];
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function getPositions(acct_id, api_key) {
|
|
|
|
|
try {
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/openPositions`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "get",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function order(acct_id, api_key, instrument, quantity) {
|
2023-07-28 11:16:12 +00:00
|
|
|
console.log("order");
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
2023-08-07 14:45:39 +00:00
|
|
|
let dist = NTP;
|
|
|
|
|
let pdist = NTP;
|
2023-07-25 18:42:23 +00:00
|
|
|
|
|
|
|
|
if (instrument.includes("JPY")) {
|
2023-08-07 14:45:39 +00:00
|
|
|
dist = NTP * 100;
|
|
|
|
|
pdist = NTP * 100;
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-25 23:22:12 +00:00
|
|
|
let data = {
|
2023-07-25 23:50:28 +00:00
|
|
|
order: {
|
2023-07-25 18:42:23 +00:00
|
|
|
/*"trailingStopLossOnFill": {
|
2023-07-25 23:50:28 +00:00
|
|
|
"timeInForce": "GTC",
|
|
|
|
|
"distance": dist
|
|
|
|
|
},*/
|
2023-07-25 18:42:23 +00:00
|
|
|
/*"takeProfitOnFill": {
|
2023-07-25 23:50:28 +00:00
|
|
|
"distance": pdist
|
|
|
|
|
},*/
|
|
|
|
|
timeInForce: "FOK",
|
|
|
|
|
instrument: instrument,
|
|
|
|
|
units: quantity,
|
|
|
|
|
type: "MARKET",
|
|
|
|
|
positionFill: "DEFAULT",
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
};
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/orders`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "post",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
data: data,
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
|
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function closeOrder(acct_id, api_key, tradeID) {
|
|
|
|
|
try {
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/close`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "put",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
console.log(response.data);
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function trailingStopLoss(acct_id, api_key, instrument) {
|
2023-07-25 23:50:28 +00:00
|
|
|
const trade = await getTradesByInstrument(acct_id, api_key, instrument);
|
2023-07-25 18:42:23 +00:00
|
|
|
const tradeID = trade.id;
|
|
|
|
|
console.log(tradeID);
|
|
|
|
|
if (!tradeID) {
|
2023-07-25 23:50:28 +00:00
|
|
|
return;
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
dist = "0.00164";
|
2023-07-25 18:42:23 +00:00
|
|
|
if (instrument.includes("JPY")) {
|
2023-07-25 23:50:28 +00:00
|
|
|
dist = "0.16";
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
try {
|
2023-07-25 23:50:28 +00:00
|
|
|
let data = {
|
|
|
|
|
trailingStopLoss: {
|
|
|
|
|
timeInForce: "GTC",
|
|
|
|
|
distance: dist,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
};
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/orders`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "put",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
data: data,
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
2023-07-25 23:50:28 +00:00
|
|
|
console.log(data);
|
2023-07-25 18:42:23 +00:00
|
|
|
console.log(response.data);
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function stopLoss(acct_id, api_key, tradeID, price) {
|
|
|
|
|
try {
|
2023-07-25 23:50:28 +00:00
|
|
|
let data = {
|
|
|
|
|
stopLoss: {
|
|
|
|
|
timeInForce: "GTC",
|
|
|
|
|
distance: "0.30",
|
2023-07-25 18:42:23 +00:00
|
|
|
//"price": price
|
2023-07-25 23:50:28 +00:00
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
};
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/orders`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "put",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
data: data,
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
2023-07-25 23:50:28 +00:00
|
|
|
console.log(data);
|
2023-07-25 18:42:23 +00:00
|
|
|
console.log(response.data);
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function takeProfit(acct_id, api_key, tradeID, dist) {
|
|
|
|
|
try {
|
2023-07-25 23:50:28 +00:00
|
|
|
let data = {
|
|
|
|
|
takeProfit: {
|
|
|
|
|
timeInForce: "GTC",
|
|
|
|
|
distance: dist,
|
|
|
|
|
},
|
2023-07-25 18:42:23 +00:00
|
|
|
};
|
|
|
|
|
const response = await axios.request({
|
|
|
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/orders`,
|
2023-07-25 23:50:28 +00:00
|
|
|
method: "put",
|
2023-07-25 18:42:23 +00:00
|
|
|
headers: {
|
2023-07-25 23:50:28 +00:00
|
|
|
Authorization: `Bearer ${api_key}`,
|
2023-07-25 18:42:23 +00:00
|
|
|
},
|
2023-07-25 23:50:28 +00:00
|
|
|
data: data,
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
2023-07-25 23:50:28 +00:00
|
|
|
return response;
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/closeAll", async (req, res) => {
|
2023-08-03 10:29:49 +00:00
|
|
|
res.json("disabled for now");
|
2023-08-03 10:12:29 +00:00
|
|
|
|
|
|
|
|
});
|
|
|
|
|
app.get("/asdfadsfasdfcloseAll", async (req, res) => {
|
|
|
|
|
|
2023-07-28 11:16:12 +00:00
|
|
|
for (const acct in STATE) {
|
2023-08-01 05:04:27 +00:00
|
|
|
for (const pair in STATE[acct]) {
|
|
|
|
|
closeOrder(
|
|
|
|
|
accounts[acct]["ACCT"],
|
|
|
|
|
accounts[acct]["APIKEY"],
|
|
|
|
|
STATE[acct][pair]["trade_id"]
|
|
|
|
|
);
|
|
|
|
|
delete STATE[acct][pair];
|
|
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
}
|
2023-07-25 23:22:12 +00:00
|
|
|
for (const account of Object.keys(accounts)) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let trades = await getTrades(
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"]
|
|
|
|
|
);
|
|
|
|
|
for (const t of trades.data["trades"]) {
|
|
|
|
|
await closeOrder(
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"],
|
|
|
|
|
t["id"]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-01 05:04:27 +00:00
|
|
|
saveState();
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
res.json("done");
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/tradesData", async (req, res) => {
|
2023-07-25 18:42:23 +00:00
|
|
|
let r = [];
|
2023-07-25 23:22:12 +00:00
|
|
|
for (const account of Object.keys(accounts)) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let response = await getTrades(
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
|
|
|
|
//Object.(response.data['trades']).forEach(([a, t]) =>{
|
2023-07-25 23:50:28 +00:00
|
|
|
response.data["trades"].forEach((t) => {
|
2023-07-25 18:42:23 +00:00
|
|
|
t["Account"] = account;
|
2023-07-25 23:50:28 +00:00
|
|
|
delete t["lastTransactionID"];
|
|
|
|
|
delete t["trailingStopLossOrder"];
|
2023-07-25 18:42:23 +00:00
|
|
|
console.log(t);
|
2023-07-25 23:50:28 +00:00
|
|
|
r.push(t);
|
2023-07-25 18:42:23 +00:00
|
|
|
});
|
|
|
|
|
} catch (error) {
|
2023-07-25 23:50:28 +00:00
|
|
|
console.log(error);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json(r);
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/transactionsAll/:account", async (req, res) => {
|
2023-07-25 18:42:23 +00:00
|
|
|
let account = req.params.account;
|
2023-07-25 23:50:28 +00:00
|
|
|
let r = {};
|
|
|
|
|
let response = await getTransactionsAll(
|
|
|
|
|
account,
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
|
|
|
|
r = {};
|
|
|
|
|
} catch (error) {
|
2023-07-25 23:50:28 +00:00
|
|
|
console.log(error);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json("ok");
|
|
|
|
|
});
|
|
|
|
|
app.get("/transactions", async (req, res) => {
|
|
|
|
|
let r = {};
|
2023-07-25 23:22:12 +00:00
|
|
|
for (const account of Object.keys(accounts)) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let response = await getTransactions(
|
|
|
|
|
account,
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
|
|
|
|
r = {};
|
|
|
|
|
} catch (error) {
|
2023-07-25 23:50:28 +00:00
|
|
|
console.log(error);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json("ok");
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/trades", async (req, res) => {
|
|
|
|
|
let r = {};
|
2023-07-25 23:22:12 +00:00
|
|
|
for (const account of Object.keys(accounts)) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let response = await getTrades(
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"]
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
try {
|
|
|
|
|
r[account] = response.data;
|
2023-08-01 05:04:27 +00:00
|
|
|
|
2023-08-03 10:29:49 +00:00
|
|
|
STATE[account] = {};
|
2023-08-03 10:12:29 +00:00
|
|
|
for (const t in response.data["trades"]) {
|
2023-08-03 10:29:49 +00:00
|
|
|
let td = response["data"]["trades"][t];
|
|
|
|
|
console.log(td);
|
|
|
|
|
//let delta = 0.0012;
|
|
|
|
|
let delta = 0;
|
|
|
|
|
let askGap = ASKGAP;
|
|
|
|
|
let bidGap = BIDGAP;
|
2023-08-07 14:45:39 +00:00
|
|
|
let ntp = NTP;
|
2023-08-01 05:04:27 +00:00
|
|
|
if (td["instrument"].includes("JPY")) {
|
2023-08-03 10:29:49 +00:00
|
|
|
//delta = 0.12;
|
|
|
|
|
delta = 0;
|
|
|
|
|
askGap = ASKGAP * 100;
|
|
|
|
|
bidGap = BIDGAP * 100;
|
2023-08-07 14:45:39 +00:00
|
|
|
ntp = NTP * 100;
|
2023-08-01 05:04:27 +00:00
|
|
|
}
|
2023-08-03 10:29:49 +00:00
|
|
|
if (typeof(STATE[account][td["instrument"]]) === 'undefined') {
|
2023-08-01 05:04:27 +00:00
|
|
|
STATE[account][td["instrument"]] = {};
|
|
|
|
|
}
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[account][td["instrument"]]["TP"] = false;
|
2023-08-01 05:06:32 +00:00
|
|
|
STATE[account][td["instrument"]]["qty"] = td["quantity"];
|
|
|
|
|
STATE[account][td["instrument"]]["trade_id"] = td["id"];
|
2023-08-03 10:12:29 +00:00
|
|
|
if (td["currentUnits"] > 0) {
|
2023-08-01 05:04:27 +00:00
|
|
|
STATE[account][td["instrument"]]["base"] = Number(td["price"]) + delta;
|
|
|
|
|
STATE[account][td["instrument"]]["watch"] = "ask";
|
2023-08-03 10:29:49 +00:00
|
|
|
STATE[account][td["instrument"]]["trigger"] = (Number(td["price"]) + delta) - askGap;
|
2023-08-03 10:12:29 +00:00
|
|
|
STATE[account][td["instrument"]]["TPVal"] = askGap;
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[account][td["instrument"]]["NTPVal"] = ntp;
|
2023-08-01 05:04:27 +00:00
|
|
|
} else {
|
|
|
|
|
STATE[account][td["instrument"]]["base"] = Number(td["price"]) - delta;
|
|
|
|
|
STATE[account][td["instrument"]]["watch"] = "bid";
|
2023-08-03 10:29:49 +00:00
|
|
|
STATE[account][td["instrument"]]["trigger"] = (Number(td["price"]) - delta) + bidGap;
|
2023-08-03 10:12:29 +00:00
|
|
|
STATE[account][td["instrument"]]["TPVal"] = bidGap;
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[account][td["instrument"]]["NTPVal"] = ntp;
|
2023-08-01 05:04:27 +00:00
|
|
|
}
|
2023-08-01 05:06:32 +00:00
|
|
|
}
|
2023-07-25 18:42:23 +00:00
|
|
|
} catch (error) {
|
2023-07-25 23:50:28 +00:00
|
|
|
console.log(error);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json(r);
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/accounts/:user_id", async (req, res) => {
|
|
|
|
|
let accts = await client.query(
|
|
|
|
|
`select * from accounts where user_id = ${req.params.user_id} `
|
|
|
|
|
);
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
2023-07-25 18:42:23 +00:00
|
|
|
res.json(accts.rows);
|
2023-07-25 23:50:28 +00:00
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/accounts", async (req, res) => {
|
|
|
|
|
let accts = await client.query(`select * from accounts `);
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
let r = {};
|
2023-07-25 18:42:23 +00:00
|
|
|
console.log(accts);
|
|
|
|
|
for (const a of accts.rows) {
|
2023-07-25 23:50:28 +00:00
|
|
|
if (typeof r[a["user_id"]] === "undefined") {
|
|
|
|
|
r[a["user_id"]] = [a];
|
2023-07-25 18:42:23 +00:00
|
|
|
} else {
|
2023-07-25 23:50:28 +00:00
|
|
|
r[a["user_id"]].push(a);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res.json(r);
|
2023-07-25 23:50:28 +00:00
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/accounts/del/:user_id/:account_id", async (req, res) => {
|
|
|
|
|
await client.query(
|
|
|
|
|
`delete from accounts where user_id = ${req.params.user_id} and id = ${req.params.account_id}`
|
|
|
|
|
);
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json("ok");
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/accounts/add/:user_id/:a_number/:akey", async (req, res) => {
|
|
|
|
|
await client.query(
|
|
|
|
|
`insert into accounts (user_id, account_number, apikey, account_type) values (${req.params.user_id},'${req.params.a_number}','${req.params.akey}', 'oanda')`
|
|
|
|
|
);
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json("ok");
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/trailingStop/:instrument", async (req, res) => {
|
2023-07-25 18:42:23 +00:00
|
|
|
const response = await trailingStopLoss(ACCT, APIKEY, req.params.instrument);
|
|
|
|
|
console.log(response);
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json(response.data);
|
|
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/tradesByInstrument/:instrument", async (req, res) => {
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
2023-07-25 18:42:23 +00:00
|
|
|
r = "";
|
|
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
data = await client.query(
|
|
|
|
|
`select * from orders where account_id = 2 and order_date > now()- interval '1 day'`
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
|
|
|
|
|
for (const row of data.rows) {
|
2023-07-25 23:50:28 +00:00
|
|
|
delete row["order_data"];
|
|
|
|
|
r += `${Object.values(row).join(",")} \n`;
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
//r[account] = await getTradesByInstrument(accounts[2]['ACCT'], accounts[2]['APIKEY'], req.params.instrument);
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Content-Type", "text/csv");
|
2023-07-25 18:42:23 +00:00
|
|
|
res.send(r);
|
2023-07-25 23:50:28 +00:00
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/prices", async (req, res) => {
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
2023-07-25 18:42:23 +00:00
|
|
|
res.json(PRICES);
|
2023-07-25 23:50:28 +00:00
|
|
|
});
|
|
|
|
|
app.get("/state", async (req, res) => {
|
|
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
2023-07-25 18:42:23 +00:00
|
|
|
res.json(STATE);
|
2023-07-25 23:50:28 +00:00
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
app.get("/order/:instrument/:quantity", async (req, res) => {
|
2023-08-03 10:12:29 +00:00
|
|
|
client.query(`insert into order_log(order_date,order_body) values (now(), $1)`, [`${req.params.instrument} ${req.params.quantity}`]);
|
2023-07-25 23:22:12 +00:00
|
|
|
let r = {};
|
|
|
|
|
for (const account of Object.keys(accounts)) {
|
2023-07-25 23:50:28 +00:00
|
|
|
let td = await getTradesByInstrument(
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"],
|
|
|
|
|
req.params.instrument
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (td == null || (td["state"] != "OPEN" && td["state"] != "PENDING")) {
|
|
|
|
|
let response = await order(
|
|
|
|
|
accounts[account]["ACCT"],
|
|
|
|
|
accounts[account]["APIKEY"],
|
|
|
|
|
req.params.instrument,
|
|
|
|
|
req.params.quantity
|
|
|
|
|
);
|
2023-07-25 18:42:23 +00:00
|
|
|
console.log(response["data"]);
|
2023-07-25 23:50:28 +00:00
|
|
|
if (typeof response["data"]["orderFillTransaction"] !== "undefined") {
|
2023-07-25 18:42:23 +00:00
|
|
|
let delta = 0.0012;
|
2023-08-03 10:29:49 +00:00
|
|
|
let askGap = ASKGAP;
|
|
|
|
|
let bidGap = BIDGAP;
|
2023-08-07 14:45:39 +00:00
|
|
|
|
|
|
|
|
let ntp = NTP;
|
2023-07-25 18:42:23 +00:00
|
|
|
if (req.params.instrument.includes("JPY")) {
|
|
|
|
|
delta = 0.12;
|
2023-08-03 10:29:49 +00:00
|
|
|
askGap = ASKGAP * 100;
|
|
|
|
|
bidGap = BIDGAP * 100;
|
2023-08-07 14:45:39 +00:00
|
|
|
ntp = ntp * 100;
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-08-03 10:29:49 +00:00
|
|
|
if (typeof(STATE[account]) === 'undefined') {
|
2023-07-26 11:27:22 +00:00
|
|
|
STATE[account] = {};
|
|
|
|
|
}
|
2023-08-03 10:29:49 +00:00
|
|
|
if (typeof(STATE[account][req.params.instrument]) === 'undefined') {
|
2023-07-26 11:27:22 +00:00
|
|
|
STATE[account][req.params.instrument] = {};
|
|
|
|
|
}
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[account][req.params.instrument]["TP"] = false;
|
2023-07-25 18:42:23 +00:00
|
|
|
STATE[account][req.params.instrument]["qty"] = req.params.quantity;
|
2023-07-25 23:50:28 +00:00
|
|
|
STATE[account][req.params.instrument]["trade_id"] =
|
|
|
|
|
response["data"]["orderFillTransaction"]["tradeOpened"]["tradeID"];
|
2023-07-25 18:42:23 +00:00
|
|
|
if (req.params.quantity > 0) {
|
2023-08-03 10:12:29 +00:00
|
|
|
STATE[account][req.params.instrument]["TPVal"] = askGap;
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[account][req.params.instrument]["NTPVal"] = ntp;
|
2023-08-01 05:04:27 +00:00
|
|
|
STATE[account][req.params.instrument]["base"] = Number(response["data"]["orderFillTransaction"]["price"]) + delta;
|
2023-07-25 18:42:23 +00:00
|
|
|
STATE[account][req.params.instrument]["watch"] = "ask";
|
2023-08-03 10:12:29 +00:00
|
|
|
STATE[account][req.params.instrument]["trigger"] = (Number(response["data"]["orderFillTransaction"]["price"]) + delta) * askGap;
|
2023-07-25 18:42:23 +00:00
|
|
|
} else {
|
2023-08-07 14:45:39 +00:00
|
|
|
STATE[account][req.params.instrument]["NTPVal"] = ntp;
|
2023-08-03 10:12:29 +00:00
|
|
|
STATE[account][req.params.instrument]["TPVal"] = bidGap;
|
2023-08-01 05:04:27 +00:00
|
|
|
STATE[account][req.params.instrument]["base"] = Number(response["data"]["orderFillTransaction"]["price"]) - delta;
|
2023-07-25 18:42:23 +00:00
|
|
|
STATE[account][req.params.instrument]["watch"] = "bid";
|
2023-08-03 10:12:29 +00:00
|
|
|
STATE[account][req.params.instrument]["trigger"] = (Number(response["data"]["orderFillTransaction"]["price"]) + delta) * bidGap;
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 23:50:28 +00:00
|
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
|
|
|
res.json("ok");
|
|
|
|
|
});
|
2023-08-07 14:45:39 +00:00
|
|
|
app.set('json spaces', 2)
|
2023-07-25 18:42:23 +00:00
|
|
|
app.listen(port, host, () => {
|
|
|
|
|
console.log(`osapi started`);
|
2023-08-07 14:45:39 +00:00
|
|
|
loadState();
|
2023-07-25 23:50:28 +00:00
|
|
|
});
|
2023-07-25 18:42:23 +00:00
|
|
|
|
2023-07-26 11:27:22 +00:00
|
|
|
|
2023-07-28 11:16:12 +00:00
|
|
|
async function price_stream() {
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`${STREAMURL_DEMO}/accounts/101-001-8005237-001/pricing/stream?instruments=GBP_CAD%2CNZD_CAD%2CEUR_CHF%2CEUR_CAD%2CNZD_CHF%2CCHF_JPY%2CUSD_CHF%2CAUD_JPY%2CEUR_USD%2CNZD_USD%2CUSD_JPY%2CGBP_AUD%2CEUR_AUD%2CCAD_JPY%2CEUR_GBP%2CAUD_CAD%2CEUR_JPY%2CAUD_CHF%2CCAD_CHF%2CGBP_JPY%2CUSD_CAD%2CNZD_JPY%2CUSD_SGD%2CAUD_USD%2CGBP_CHF%2CAUD_NZD%2CGBP_USD`, {
|
2023-08-03 10:29:49 +00:00
|
|
|
method: "GET",
|
|
|
|
|
headers: {
|
|
|
|
|
Authorization: "Bearer e88218d201bd344c2dc3c469f8f8d1f3-e77504680a17f51f0baecf9dababa40b",
|
|
|
|
|
},
|
|
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
);
|
|
|
|
|
try {
|
|
|
|
|
for await (const chunk of response.body) {
|
|
|
|
|
try {
|
|
|
|
|
const x = JSON.parse(chunk.toString());
|
|
|
|
|
if (x["type"] == "PRICE") {
|
|
|
|
|
let delta = x["asks"][0]["price"] - x["bids"][0]["price"];
|
|
|
|
|
client.query(
|
|
|
|
|
`insert into pricing (instrument, price_data, tick, bid,ask,spread) values ($1,$2,$3,$4,$5,$6)`,
|
|
|
|
|
[
|
|
|
|
|
x["instrument"],
|
|
|
|
|
x,
|
|
|
|
|
x["time"],
|
|
|
|
|
x["asks"][0]["price"],
|
|
|
|
|
x["bids"][0]["price"],
|
|
|
|
|
delta.toFixed(6),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
PRICES[x["instrument"]] = {
|
2023-08-01 05:04:27 +00:00
|
|
|
ask: Number(x["asks"][0]["price"]),
|
|
|
|
|
bid: Number(x["bids"][0]["price"]),
|
2023-07-28 11:16:12 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
|
|
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.log("pricing error");
|
|
|
|
|
console.error(err);
|
|
|
|
|
console.error(err.stack);
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
2023-07-28 11:16:12 +00:00
|
|
|
|
|
|
|
|
return await price_stream();
|
2023-07-25 18:42:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-28 11:16:12 +00:00
|
|
|
|
2023-08-07 14:45:39 +00:00
|
|
|
loadState()
|
2023-07-28 11:16:12 +00:00
|
|
|
await price_stream();
|