490 lines
14 KiB
JavaScript
490 lines
14 KiB
JavaScript
const express = require('express')
|
|
var cors = require('cors')
|
|
var fs = require('fs')
|
|
var morgan = require('morgan')
|
|
var path = require('path')
|
|
const app = express()
|
|
|
|
|
|
var pg = require('pg');
|
|
const client = new pg.Client({
|
|
host: 'citus1.home.neb',
|
|
port: 5432,
|
|
database: 'oversite',
|
|
user: 'postgres',
|
|
})
|
|
|
|
|
|
client.connect()
|
|
|
|
const port = 3000
|
|
const host = "0.0.0.0"
|
|
|
|
|
|
|
|
var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' })
|
|
|
|
app.use(morgan('combined', { stream: accessLogStream }))
|
|
|
|
const axios = require('axios').default;
|
|
|
|
|
|
const APIURL = 'https://api-fxpractice.oanda.com/v3'
|
|
const accounts = {
|
|
'1': {
|
|
'ACCT': '101-001-8005237-001',
|
|
'APIKEY': '85397a3ddc7b96ef57b90c9feda6d410-18f0f2b634f9f05533d2c20046bb79df'
|
|
},
|
|
'2': {
|
|
'APIKEY': 'b954456a3f4ac735de2555e1af50abf7-ed83ace2f9fb86412b76608daefc73a5',
|
|
'ACCT': '101-001-23367262-002'
|
|
},
|
|
'3': {
|
|
'APIKEY': 'd4ea6095fe8017841279416437520aee-fa23a0556fb501520ceedbff5f405267',
|
|
'ACCT': '101-002-26241098-001'
|
|
}
|
|
}
|
|
|
|
async function getTransactionsAll(account,acct_id, api_key) {
|
|
for (const rg of [...Array(32).keys()]) {
|
|
try {
|
|
f = rg * 1000 + 1;
|
|
to = f + 1000;
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/transactions/idrange?from=${f}&to=${to}`,
|
|
method: 'get',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
}
|
|
});
|
|
|
|
for (const t of response.data.transactions){
|
|
qty = 0;
|
|
tp = "";
|
|
if(typeof(t['instrument']) !== undefined){
|
|
tp = t['instrument']
|
|
}
|
|
if(typeof(t['units']) !== undefined){
|
|
qty = t['units']
|
|
}
|
|
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]);
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
}
|
|
}
|
|
async function getTransactions(account,acct_id, api_key) {
|
|
// for (const rg of [...Array(32).keys()]) {
|
|
try {
|
|
console.log(`SELECT max(order_id) from orders where account_id = ${account}`);
|
|
const res = await client.query(`SELECT max(order_id) as order_id from orders where account_id = ${account}`)
|
|
console.log(res.rows[0].order_id) // Hello w
|
|
console.log(res.rows[0]) // Hello w
|
|
f = res.rows[0].order_id;
|
|
to = f + 1000;
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/transactions/idrange?from=${f}&to=${to}`,
|
|
method: 'get',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
}
|
|
});
|
|
|
|
for (const t of response.data.transactions){
|
|
qty = 0;
|
|
tp = "";
|
|
if(typeof(t['instrument']) !== undefined){
|
|
tp = t['instrument']
|
|
}
|
|
if(typeof(t['units']) !== undefined){
|
|
qty = t['units']
|
|
}
|
|
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]);
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function getTrades(acct_id, api_key) {
|
|
try {
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/openTrades`,
|
|
method: 'get',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
}
|
|
});
|
|
return (response)
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
async function getTradesByInstrument(acct_id, api_key, instrument) {
|
|
try {
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/trades?instrument=${instrument}`,
|
|
method: 'get',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
}
|
|
});
|
|
console.log(response)
|
|
if (response.data.trades.length == 0) {
|
|
return
|
|
} else {
|
|
|
|
return (response.data.trades[0])
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
async function getPositions(acct_id, api_key) {
|
|
try {
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/openPositions`,
|
|
method: 'get',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
}
|
|
});
|
|
return (response);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
async function order(acct_id, api_key, instrument, quantity) {
|
|
try {
|
|
|
|
|
|
let dist = "0.0005"
|
|
let pdist = "0.0005"
|
|
|
|
if (instrument.includes("JPY")) {
|
|
dist = "0.05"
|
|
pdist = "0.05"
|
|
}
|
|
|
|
|
|
data = {
|
|
"order": {
|
|
"trailingStopLossOnFill": {
|
|
"timeInForce": "GTC",
|
|
"distance": dist
|
|
},
|
|
/*"takeProfitOnFill": {
|
|
"distance": pdist
|
|
},*/
|
|
"timeInForce": "FOK",
|
|
"instrument": instrument,
|
|
"units": quantity,
|
|
"type": "MARKET",
|
|
"positionFill": "DEFAULT"
|
|
}
|
|
};
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/orders`,
|
|
method: 'post',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
},
|
|
data: data
|
|
});
|
|
console.log(data)
|
|
return (response)
|
|
/*try {
|
|
delta = response.data.orderFillTransaction.price * .00164;
|
|
price = response.data.orderFillTransaction.price;
|
|
units = response.data.orderFillTransaction.units;
|
|
pres = price.toString().split('.')[1].length
|
|
if (units > 0) {
|
|
price = price - delta;
|
|
} else {
|
|
price = price + delta
|
|
}
|
|
return await stopLoss(acct_id, api_key, response.data.orderFillTransaction.id, Number(price).toFixed(pres).toString())
|
|
} catch (error) {
|
|
console.log(error)
|
|
return (error)
|
|
}*/
|
|
|
|
} 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`,
|
|
method: 'put',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
},
|
|
});
|
|
console.log(response.data);
|
|
return (response);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
}
|
|
|
|
async function trailingStopLoss(acct_id, api_key, instrument) {
|
|
const trade = await getTradesByInstrument(acct_id, api_key, instrument)
|
|
const tradeID = trade.id;
|
|
console.log(tradeID);
|
|
if (!tradeID) {
|
|
return
|
|
}
|
|
dist = "0.00164"
|
|
if (instrument.includes("JPY")) {
|
|
dist = "0.16"
|
|
}
|
|
try {
|
|
data = {
|
|
"trailingStopLoss": {
|
|
"timeInForce": "GTC",
|
|
"distance": dist
|
|
}
|
|
};
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/orders`,
|
|
method: 'put',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
},
|
|
data: data
|
|
});
|
|
console.log(data)
|
|
console.log(response.data);
|
|
return (response);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
}
|
|
|
|
async function stopLoss(acct_id, api_key, tradeID, price) {
|
|
try {
|
|
data = {
|
|
"stopLoss": {
|
|
"timeInForce": "GTC",
|
|
"distance": "0.30"
|
|
//"price": price
|
|
}
|
|
};
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/orders`,
|
|
method: 'put',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
},
|
|
data: data
|
|
});
|
|
console.log(data)
|
|
console.log(response.data);
|
|
return (response);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
}
|
|
|
|
async function takeProfit(acct_id, api_key, tradeID, dist) {
|
|
try {
|
|
data = {
|
|
"takeProfit": {
|
|
"timeInForce": "GTC",
|
|
"distance": dist
|
|
}
|
|
};
|
|
const response = await axios.request({
|
|
url: `${APIURL}/accounts/${acct_id}/trades/${tradeID}/orders`,
|
|
method: 'put',
|
|
headers: {
|
|
'Authorization': `Bearer ${api_key}`
|
|
},
|
|
data: data
|
|
});
|
|
return (response);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
}
|
|
|
|
app.get('/closeAll', async (req, res) => {
|
|
|
|
for (account of Object.keys(accounts)) {
|
|
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'])
|
|
}
|
|
}
|
|
|
|
res.json('done')
|
|
})
|
|
|
|
|
|
app.get('/tradesData', async (req, res) => {
|
|
|
|
let r = [];
|
|
for (account of Object.keys(accounts)) {
|
|
let response = await getTrades(accounts[account]['ACCT'], accounts[account]['APIKEY'])
|
|
try {
|
|
//Object.(response.data['trades']).forEach(([a, t]) =>{
|
|
response.data['trades'].forEach(( t) =>{
|
|
|
|
t["Account"] = account;
|
|
delete t['lastTransactionID'];
|
|
delete t['trailingStopLossOrder'];
|
|
console.log(t);
|
|
r.push(t)
|
|
});
|
|
|
|
} catch(error) {
|
|
console.log(error)
|
|
}
|
|
}
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
res.json(r)
|
|
})
|
|
|
|
|
|
app.get('/transactionsAll/:account', async (req, res) => {
|
|
|
|
let r = {}
|
|
let response = await getTransactions(account,accounts[account]['ACCT'], accounts[account]['APIKEY'])
|
|
try {
|
|
r = {};
|
|
} catch(error) {
|
|
console.log(error)
|
|
}
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
res.json("ok")
|
|
})
|
|
app.get('/transactions', async (req, res) => {
|
|
|
|
let r = {}
|
|
for (account of Object.keys(accounts)) {
|
|
let response = await getTransactions(account,accounts[account]['ACCT'], accounts[account]['APIKEY'])
|
|
try {
|
|
r = {};
|
|
} catch(error) {
|
|
console.log(error)
|
|
}
|
|
}
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
res.json("ok")
|
|
})
|
|
|
|
app.get('/trades', async (req, res) => {
|
|
|
|
let r = {}
|
|
for (account of Object.keys(accounts)) {
|
|
let response = await getTrades(accounts[account]['ACCT'], accounts[account]['APIKEY'])
|
|
try {
|
|
r[account] = response.data;
|
|
} catch(error) {
|
|
console.log(error)
|
|
}
|
|
}
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
res.json(r)
|
|
})
|
|
|
|
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');
|
|
})
|
|
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');
|
|
})
|
|
|
|
app.get('/trailingStop/:instrument', async (req, res) => {
|
|
const response = await trailingStopLoss(ACCT, APIKEY, req.params.instrument);
|
|
console.log(response);
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
res.json(response.data)
|
|
})
|
|
app.get('/tradesByInstrument/:instrument', async (req, res) => {
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
r = {};
|
|
for (account of Object.keys(accounts)) {
|
|
r[account] = await getTradesByInstrument(accounts[account]['ACCT'], accounts[account]['APIKEY'], req.params.instrument);
|
|
}
|
|
res.json(r);
|
|
})
|
|
app.get('/order/:instrument/:quantity', async (req, res) => {
|
|
|
|
|
|
r = {};
|
|
/*td = await getTradesByInstrument(accounts['2']['ACCT'], accounts['1']['APIKEY'], req.params.instrument);
|
|
if (td) {
|
|
|
|
if (td["initialUnits"] != req.params.quantity) {
|
|
let dist = "0.005"
|
|
if (req.params.instrument.includes("JPY")) {
|
|
let dist = "0.5"
|
|
}
|
|
await takeProfit(accounts['2']['ACCT'], accounts['1']['APIKEY'], td["id"], dist)
|
|
}
|
|
} else {
|
|
response = await order(accounts['2']['ACCT'], accounts['1']['APIKEY'], req.params.instrument, req.params.quantity);
|
|
}*/
|
|
/*td = await getTradesByInstrument(accounts['2']['ACCT'], accounts['2']['APIKEY'], req.params.instrument);
|
|
if (td) {
|
|
|
|
if (td["initialUnits"] != req.params.quantity) {
|
|
let dist = "0.005"
|
|
if (req.params.instrument.includes("JPY")) {
|
|
|
|
let dist = "0.5"
|
|
}
|
|
await takeProfit(accounts['2']['ACCT'], accounts['2']['APIKEY'], td["id"], dist)
|
|
}
|
|
} else {
|
|
|
|
response = await order(accounts['2']['ACCT'], accounts['2']['APIKEY'], req.params.instrument, req.params.quantity);
|
|
} */
|
|
for (account of Object.keys(accounts)) {
|
|
td = await getTradesByInstrument(accounts[account]['ACCT'], accounts[account]['APIKEY'], req.params.instrument);
|
|
if (td['state'] != "OPEN" || td['state'] != "PENDING") {
|
|
response = await order(accounts[account]['ACCT'], accounts[account]['APIKEY'], req.params.instrument, req.params.quantity);
|
|
}
|
|
}
|
|
|
|
|
|
res.header('Access-Control-Allow-Origin', '*')
|
|
|
|
|
|
res.json("ok")
|
|
|
|
})
|
|
|
|
app.listen(port, host, () => {
|
|
console.log(`osapi started`);
|
|
})
|