GithubHelp home page GithubHelp logo

reiryoku-technologies / mida Goto Github PK

View Code? Open in Web Editor NEW
339.0 15.0 42.0 2.92 MB

The open-source and cross-platform trading engine ๐Ÿ“ˆ

Home Page: https://www.mida.org

License: MIT License

TypeScript 97.19% JavaScript 0.35% Python 0.02% C++ 2.40% CMake 0.05%
forex typescript framework finance trading stocks nodejs javascript financial-markets broker crypto cryptocurrency bitcoin trading-bot exchange web3 algotrading binance-api bybit-api ctrader

mida's Introduction



Mida Mida


The open-source and cross-platform trading engine ๐Ÿ“ˆ

Home โ€” Documentation โ€” API




Table of Contents

Introduction

Mida is an open-source and cross-platform trading engine developed by Reiryoku Technologies and its contributors. Designed from the ground up to provide a solid, versatile and platform-neutral environment for creating algorithmic and quantitative trading systems, indicators, market analysis tools or just trading applications depending on use cases.

Would you like to honor our efforts? If so, you can leave a star on GitHub โญ. Thank you!

Languages

Mida is used with JavaScript/TypeScript on Node.js and can be additionally enhanced with C++.
Why JavaScript/TypeScript?

Platforms

Mida is platform-neutral, this means trading platforms could be easily integrated into the engine. Applications built with Mida can be easily executed on different trading platforms.





Community

Join the community on Discord and Telegram to get help you with your first steps.

Installation

Mida is distributed on npm and can be installed in just one step.

npm install @reiryoku/mida

Usage

Account connection

How to connect to a Binance Spot account,
read how to use Mida with Binance to get your apiKey and apiSecret credentials.

import { connect, } from "@reiryoku/mida";

const myAccount = await connect("Binance/Spot", {
    apiKey: "***",
    apiSecret: "***",
});

How to connect to a cTrader account,
read how to use Mida with cTrader to get your clientId, clientSecret, accessToken and accountId credentials.

import { connect, } from "@reiryoku/mida";

const myAccount = await connect("cTrader", {
    clientId: "***",
    clientSecret: "***",
    accessToken: "***",
    accountId: "***",
});

How to connect to a Bybit Futures account,
read how to use Mida with Bybit to get your apiKey and apiSecret credentials.

import { connect, } from "@reiryoku/mida";

const myAccount = await connect("Bybit/Futures", {
    apiKey: "***",
    apiSecret: "***",
});

How to connect to multiple accounts.

import { connect, } from "@reiryoku/mida";

const myAccount1 = await connect("Binance/Spot", { /* ... */ });
const myAccount2 = await connect("Bybit/Futures", { /* ... */ });
const myAccount3 = await connect("cTrader", { /* ... */ });

Balance, equity and margin

How to get the account balance, equity and margin.

const balance = await myAccount.getBalance();
const equity = await myAccount.getEquity();
const freeMargin = await myAccount.getFreeMargin();
const usedMargin = await myAccount.getUsedMargin();

Orders, trades and positions

How to buy 1 Bitcoin (opening a long position for BTC/USDT).

import { MidaOrderDirection, } from "@reiryoku/mida";

const myOrder = await myAccount.placeOrder({
    symbol: "BTCUSDT",
    direction: MidaOrderDirection.BUY,
    volume: 1,
});

const orderId = myOrder.id;
const executionPrice = myOrder.executionPrice;
const filledVolume = myOrder.filledVolume;
const trades = myOrder.trades;
const myPosition = await order.getPosition();

How to open a short position for EUR/USD.

import { MidaOrderDirection, } from "@reiryoku/mida";

const myOrder = await myAccount.placeOrder({
    symbol: "EURUSD",
    direction: MidaOrderDirection.SELL,
    volume: 0.1,
});

const orderId = myOrder.id;
const executionPrice = myOrder.executionPrice;
const filledVolume = myOrder.filledVolume;
const trades = myOrder.trades;
const myPosition = await order.getPosition();

How to open a long position for ETH/USDT with error handler.

import {
    MidaOrderDirection,
    MidaOrderRejection,
} from "@reiryoku/mida";

const myOrder = await myAccount.placeOrder({
    symbol: "ETHUSDT",
    direction: MidaOrderDirection.BUY,
    volume: 888,
});

if (myOrder.isRejected) {
    switch (myOrder.rejection) {
        case MidaOrderRejection.MARKET_CLOSED: {
            console.log("The market is closed!");

            break;
        }
        case MidaOrderRejection.NOT_ENOUGH_MONEY: {
            console.log("You don't have enough money in your account!");

            break;
        }
        case MidaOrderRejection.SYMBOL_NOT_FOUND: {
            console.log("Your account doesn't support trading Ethereum!");

            break;
        }
    }
}
More examples

How to open a long position for GBP/USD with stop loss and take profit.

import { MidaOrderDirection, } from "@reiryoku/mida";

const symbol = "GBPUSD";
const lastBid = await myAccount.getSymbolBid(symbol);
const myOrder = await myAccount.placeOrder({
    symbol,
    direction: MidaOrderDirection.BUY,
    volume: 0.1,
    limit: lastBid, // Limit order, remove to place a market order
    protection: {
        stopLoss: lastBid.sub(0.0010), // <= SL 10 pips
        takeProfit: lastBid.add(0.0030), // <= TP 30 pips
    },
});

How to close an open position.

import {
    MidaOrderDirection,
    MidaPositionDirection,
} from "@reiryoku/mida";

await myPosition.close();
// or
await myPosition.subtractVolume(myPosition.volume);
// or
await myAccount.placeOrder({
    positionId: myPosition.id,
    direction: myPosition.direction === MidaPositionDirection.LONG ? MidaOrderDirection.SELL : MidaOrderDirection.BUY,
    volume: myPosition.volume,
});

How to retrieve all pending orders and open positions.

const pendingOrders = await myAccount.getPendingOrders();
const openPositions = await myAccount.getOpenPositions();

How to set/change take profit and stop loss for an open position.

await myPosition.changeProtection({
    takeProfit: 200,
    stopLoss: 100,
});

Decimals

Computers can only natively store integers, so they need some way of representing decimal numbers. This representation is not perfectly accurate. This is why, in most programming languages 0.1 + 0.2 != 0.3, for financial and monetary calculations this can lead to unreversible losses.
In Mida, decimal numbers and calculations are safe by design and accurately represented by the MidaDecimal API.

import { decimal, } from "@reiryoku/mida";

// BAD (native behaviour)
0.1 + 0.2; // 0.30000000000000004

// GOOD (with Mida decimals)
decimal(0.1).add(0.2); // 0.3

// GOOD (with Mida decimals)
decimal("0.1").add("0.2"); // 0.3

In Mida, every calculation under the hood is made using decimals and every native number passed to Mida is internally converted to decimal, input values in the Mida APIs such as a limit price are usually expressed as a MidaDecimalConvertible which is an alias for MidaDecimal | string | number, the input values are internally converted to MidaDecimal and most Mida interfaces exposes decimal numbers unless otherwise stated.

Read more about the Decimals API.

Symbols and assets

How to retrieve all symbols available for your trading account.

const symbols = await myAccount.getSymbols();

How to retrieve a complete symbol.

const symbol = await myAccount.getSymbol("#AAPL");

if (!symbol) {
    console.log("Apple stocks are not available for this account!");
}
else {
    console.log(symbol.baseAsset);
    console.log(symbol.quoteAsset);
    console.log(symbol.digits);
    console.log(symbol.minLots); // Min volume for an order
    console.log(symbol.maxLots); // Max volume for an order
    console.log(symbol.pipPosition);
    console.log(await symbol.isMarketOpen());
}

How to get the price of a symbol.

const price = await myAccount.getSymbolBid("BTCUSDT");
// or
const symbol = await myAccount.getSymbol("BTCUSDT");
const price = await symbol.getBid();

console.log(`Bitcoin price is ${price} USDT`);

Ticks and candlesticks

How to listen the real-time ticks of a symbol.

import { watchTicks, } from "@reiryoku/mida";

const watcher = await marketWatcher({ tradingAccount: myAccount, });

await watcher.watch("BTCUSDT", { watchTicks: true, });

watcher.on("tick", (event) => {
    const { tick, } = event.descriptor;

    console.log(`Bitcoin price is now ${tick.bid} USDT`);
});

Furthermore, ticks can be directly listened using the watchTicks() shorthand.

import { watchTicks, } from "@reiryoku/mida";

watchTicks(myAccount, "BTCUSDT", (event) => {
    const { tick, } = event.descriptor;

    console.log(`Bitcoin price is now ${tick.bid} USDT`);
});

How to listen the real-time candlesticks of a symbol (when the last live candlesticks are updated/closed).

import {
    marketWatcher,
    MidaTimeframe,
} from "@reiryoku/mida";

const watcher = await marketWatcher({ tradingAccount: myAccount, });

await watcher.watch("BTCUSDT", {
    watchPeriods: true,
    timeframes: [
        MidaTimeframe.M5,
        MidaTimeframe.H1,
    ],
});

watcher.on("period-update", (event) => {
    const { period, } = event.descriptor;

    switch (period.timeframe) {
        case MidaTimeframe.M5: {
            console.log("Last live M5 candlestick updated");

            break;
        }
        case MidaTimeframe.H1: {
            console.log("Last live M5 candlestick updated");

            break;
        }
    }
});

watcher.on("period-close", (event) => {
    const { period, } = event.descriptor;

    switch (period.timeframe) {
        case MidaTimeframe.M5: {
            console.log(`M5 candlestick closed at ${period.close}`);

            break;
        }
        case MidaTimeframe.H1: {
            console.log(`H1 candlestick closed at ${period.close}`);

            break;
        }
    }
});

How to get the historical closed candlesticks of a symbol (in Mida, candlesticks and bars are generically called periods).

import { MidaTimeframe, } from "@reiryoku/mida";

const periods = await myAccount.getSymbolPeriods("EURUSD", MidaTimeframe.M30);
const lastPeriod = periods.at(-1);

console.log("Last candlestick start time: " + lastPeriod.startTime);
console.log("Last candlestick OHLC: " + lastPeriod.ohlc);
console.log("Last candlestick close price: " + lastPeriod.close);

When listening events in Mida, the on() method returns an id which can be used later to unsubscribe from the event listener.

const id = watcher.on("period-close", (event) => { /* ... */ });

watcher.removeEventListener(id);

Market components

A market component is way to encapsulate logic and data reactively evolving as the underlying market changes. Market components can be used to easily create trading systems and independent market analysis logic.

Read more about Reactive Programming in Financial Markets.

How to create a market component detecting overbought markets

import { marketComponent, } from "@reiryoku/mida";

// A reactive component detecting overbought markets
const OverboughtDetector = marketComponent({
    indicators: {
        myIndicator: {
            type: "RSI",
            options: { length: 14, },
            input: {
                timeframe: MidaTimeframe.M30, // Use M30 candles
                type: "close", // Use close prices
            },
        },
    },
    computed: {
        // A variable calculated every market update
        isOverbought () {
            return this.myIndicator.lastValue.greaterThan(80);
        },
    },
    // A hook fired once in the component's lifetime, use as async constructor
    async created () {
        console.log("Hello World!");
    },
    // A hook fired every market update (market ticks, closed candles...)
    async update () {
        console.log(this.isOverbought);
    },
    // A targeted hook fired every candle close
    async periodClose$M15 (period) {
        console.log("Closed M15 candle");
    }
});

How to execute a market component

const overboughtDetector = await OverboughtDetector(myAccount, "ETHUSD");

How to create a simple market ticker

import { marketComponent, } from "@reiryoku/mida";

// A component logging the market prices
const Ticker = marketComponent({
    computed: {
        spread () {
            return this.$ask.sub(this.$bid);
        },
    },
    update () {
        console.log(`Market price has changed for symbol ${this.$symbol}`);

        console.log(`Bid price is ${this.$bid}`);
        console.log(`Ask price is ${this.$ask}`);

        console.log(`The spread is ${this.spread}`);
    },
});

The this of a market component assumes the state of the component which is composed by data such as computed variables, indicators and methods, plus some builtin variables such as the current candles, bid and ask prices of the market, which are self-updating in response to market updates.

// The builtin market component variables
type MidaMarketComponentState = Record<string, any> & {
    $component: MidaMarketComponent;
    $dependencies: MidaMarketComponentState[];
    $tradingAccount: MidaTradingAccount;
    $watcher: MidaMarketWatcherDirectives;
    $symbol: string;
    $bid: MidaDecimal;
    $ask: MidaDecimal;
    $ticks: MidaTick[];
    $periods: Record<MidaTimeframe, MidaPeriod[]>;
    $livePeriods: Record<MidaTimeframe, MidaPeriod>;
    $indicators: Record<string, MidaIndicator>;
};

Market component hooks

The update() hook is triggered by various market events, such as a market tick, the closing of a candle, or the opening or closing of the market itself. Consequently, each market event corresponds to its own specific hook.

import { marketComponent, } from "@reiryoku/mida";

const Component = marketComponent({
    async tick () {
        // Fired when there is a market tick
    },

    async periodUpdate (period) {
        // Fired when a last live candlestick is updated
    },

    async periodClose (period) {
        // Fired when a candlestick is closed
    },

    // Furthermore, specific timeframes can be targeted
    async periodClose$M15 (period) {
        // Fired when a M15 candlestick is closed
    },

    async marketOpen () {
        // Fired when the market opens
    },

    async update () {
        // Fired when there is any market update of the above
    },
});

Read more about Reactive Programming in Financial Markets.

Trading systems

How to create a trading system (expert advisor or trading bot).
Trading systems are used under the hood to regulate and execute market components. It's recommended to use the Market Components API over the Trading Systems API as it allows to quickly develop and maintain an idea in a declarative way.

import {
    MidaTradingSystem,
    MidaTimeframe,
} from "@reiryoku/mida";

class SuperTradingSystem extends MidaTradingSystem {
    watched () {
        return {
            "BTCUSDT": {
                watchTicks: true,
                watchPeriods: true,
                timeframes: [ MidaTimeframe.H1, ],
            },
        };
    }

    async configure () {
        // Called once per instance before the first startup
        // can be used as async constructor
    }

    async onStart () {
        console.log("The trading system has started...");
    }

    async onTick (tick) {
        // Implement your strategy
    }

    async onPeriodClose (period) {
        console.log(`H1 candlestick closed at ${period.open}`);
    }

    async onStop () {
        console.log("The trading system has been interrupted...");
    }
}

How to execute a trading system.

import { connect, } from "@reiryoku/mida";
import { SuperTradingSystem, } from "./SuperTradingSystem";

const myAccount = await connect(/* ... */);
const mySystem = new SuperTradingSystem({ tradingAccount: myAccount, });

await mySystem.start();

Paper trading and backtesting

Mida comes with an out of the box simulator of exchanges and spot trading accounts, for paper trading and backtesting read Paper Trading with Mida.

Technical indicators

Mida comes with builtin indicators written in C for native performance. Additionally, new indicators can be created.

How to calculate SMA (Simple Moving Average).

import { Mida, MidaTimeframe, } from "@reiryoku/mida";

// Get latest candlesticks on H1 timeframe
const candlesticks = await myAccount.getSymbolPeriods("EURUSD", MidaTimeframe.H1);
const closePrices = candlesticks.map((candlestick) => candlestick.close);

// Calculate RSI on close prices, pass values from oldest to newest
const sma = await Mida.createIndicator("SMA").calculate(closePrices);

// Values are from oldest to newest
console.log(sma);

How to calculate RSI (Relative Strength Index).

import { Mida, MidaTimeframe, } from "@reiryoku/mida";

// Get latest candlesticks on H1 timeframe
const candlesticks = await myAccount.getSymbolPeriods("BTCUSDT", MidaTimeframe.H1);
const closePrices = candlesticks.map((candlestick) => candlestick.close);

// Calculate RSI on close prices, pass values from oldest to newest
const rsi = await Mida.createIndicator("RSI", { period: 14, }).calculate(closePrices);

// Values are from oldest to newest
console.log(rsi);

Why JavaScript/TypeScript?

At Reiryoku Technologies we hold the firm belief that JavaScript/TypeScript is the optimal choice for algorithmic trading in financial markets, due to several key factors:

Firstly, the language's easy learning curve empowers traders to focus on developing effective strategies without being encumbered by intricate technicalities such as memory management. This streamlined learning experience accelerates the deployment of trading algorithms, enabling market participants to swiftly adapt to dynamic market conditions.

Secondly, JavaScript/TypeScript excels in managing networking capabilities and handling asynchronous tasks, making it a formidable choice for algorithmic trading. Its robust networking capabilities facilitate real-time data processing and seamless communication, allowing traders to swiftly access and analyze market information. The language's efficient handling of asynchronous tasks enables simultaneous management of multiple market feeds, execution of trades, and response to market events, ensuring optimal performance and responsiveness.

Finally, we designed Mida offering the flexibility to use C++, this integration allows for enhanced performance optimizations combined with the strengths of JavaScript/TypeScript for rapid development and strategy-focused programming.

License and disclaimer

LICENSE

Trading in financial markets is highly speculative and carries a high level of risk. It's possible to lose all your capital. This project may not be suitable for everyone, you should ensure that you understand the risks involved. Mida, Reiryoku Technologies and its contributors are not responsible for any technical inconvenience that may lead to money loss, for example a stop loss not being set.

Contributors

Name or Username Contribution GitHub Contact
Vasile Peศ™te Founder and maintainer Vasile-Peste [email protected]
dbvcode Collaborator dbvcode /
Karsten Jakobsen Collaborator karstenjakobsen /
JoeGuest Collaborator JoeGuest /
Yannick Jemmely Collaborator yannickjemmely /
Lorenzo Iovino Collaborator lokenxo /

Keywords

Algotrading Node.js, Binance Node.js API, cTrader Node.js API, Bybit Node.js API, bitFlyer Node.js API

mida's People

Contributors

dbvcode avatar joeguest avatar karstenjakobsen avatar lokenxo avatar vasile-peste avatar yannickjemmely avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mida's Issues

Help with Backtester - Question

Hi,

Could anyone help me understand the way the backtester works after a trade?

What I am trying to understand is why the balance of my paper trading account is not what I am expecting. I am adding some code below with the hope someone can enlighten me.

So this is what I am doing:

1 - Start account with 50.000USD;
2 - Elapse 5 minutes;
3 - Checking the price of asset (in my case GER40, Price is 15483.631
4 - Placing a Sell order with 0.1 Volume.
5 - Elapsing 5 hours;
6 - Price is 15443.911
6 - Checking balance - End Balance is 51548.

Since the price decreased by 40 pips, why is my balance +1548? Shouldnโ€™t it be (volume * pips)??

Unless any part of my code is wrong or missing, I fail to understand the logic.

Could anybody help?

Code is below:

`const symbolParameters = {
symbol: "GER40",
baseAsset: "USD",
quoteAsset: "USD",
description: "",
leverage: decimal(0),
minLots: decimal(1),
maxLots: decimal(1),
lotUnits: decimal(0),
pipPosition: -1,
digits: 2,
};
const rawPeriods = await readPeriodCsv("periods.csv")

const engine = new MidaPlaygroundEngine({
    localDate: date("2023-03-10"),
});

await engine.addSymbolPeriods("GER40",rawPeriods)

const myAccount = new MidaPlaygroundAccount({
  id:"my-super-account",
  primaryAsset: "USD",
  engine: engine,
  balanceSheet: {
    "USD": 0
  },
})

await myAccount.deposit("USD",50000)

console.log(await myAccount.id)
console.log(await myAccount.getBalance())

await engine.elapseTime(300); 

await myAccount.addSymbol(symbolParameters)

console.log(`Price is ${await engine.getSymbolBid("GER40")}`) //15483.631

await myAccount.placeOrder({
    symbol: "GER40",
    direction: MidaOrderDirection.SELL,
    volume: 0.1,
});

await engine.elapseTime(18000); 

console.log(`Price is ${await engine.getSymbolBid("GER40")}`) //15443.911

console.log(await myAccount.getBalance())`

Changing the label field

Screen Shot 2022-06-16 at 6 42 43 AM

It would be nice if we can change labels when placing new orders.
The use case: We can add, for example, the indicators or the reasons why we opened this order.
Later, we can use this label to close/cancel the orders.

Thanks

isMarketOpen() always return true

Hi,
The function isMarketOpen() always return true.Tested with cTrader/FPMarkets account/US100 symbol.
The only real possibility to check if the market is open at this time is to place a order and test the reject reason
if (myOrder.isRejected) {
switch (myOrder.rejection) {
case MidaOrderRejection.MARKET_CLOSED: {
isMarketOpen=false;
break;
}
}
}
MIDA version 2023.8.0

Thanks

marketWatcher.on("period-close"...) emits wrong timeframe

This one used to work for sure, but does not work as it should anymore.

marketWatcher.watch(symbol, {
        watchPeriods: true,
        watchTicks: true,
        timeframes: [300] //5m
    });

marketWatcher.on("period-close", (event) => {
        const candle = event.descriptor.period as MidaPeriod;
        console.log('period close',candle.timeframe);
});

This one does indeed emit when the 5m candle closes, but the timeframe on the candle says 60 instead of 300.
If I subscribe to multiple timeframes they all say they are 60.

cTrader token expiration date

After using Mida for a while I got into this new scenario where my cTrader token expired.
I got an error that is nice:

{
  payloadType: 'PROTO_OA_ERROR_RES',
  ctidTraderAccountId: null,
  errorCode: 'CH_ACCESS_TOKEN_INVALID',
  description: 'Access token expired',
  maintenanceEndTimestamp: null,
  clientMsgId: '17296c10-0e41-11ed-25fb-85baec39168c'
}

And now the question arises,
Is there a way to know the validity of the token from the Mida instance?
It would be very nice to prevent this from happening in production and every time I start the app run something like account.getTokenValidity() and know when it will expire so I issue a new token a few hours before it does.

Can this be done? Do you think it's a good idea?

REQUEST_FREQUENCY_EXCEEDED on getOrders()

This is funny. If I run a getOrders() on Pepperstone with cTrader I instantly get:

{
  payloadType: 'PROTO_OA_ERROR_RES',
  ctidTraderAccountId: '0',
  errorCode: 'REQUEST_FREQUENCY_EXCEEDED',
  description: 'You have reached the rate limit of requests',
  maintenanceEndTimestamp: null,
  clientMsgId: 'bef1d2f0-dcc5-11ec-b2d2-0da955e5ed11'
}

But other methods work and don't cause this issue. I can assure you it's not a request frequency issue. I just made this call and that's it.

Error setStopLoss

Hello, how are you? I have error in my code, when I try set stop loss, follow error below:

Captura de tela 2022-08-19 152909

you can help me?

Thanks!

placeOrder() timeInForce has no effect

I tried placing an order with cTrader on Pepperstone like:

account.placeOrder({
            direction: MidaOrderDirection.SELL,
            volume: 1,
            symbol: 'GER40',
            limit: 13500,
            timeInForce: MidaOrderTimeInForce.GOOD_TILL_DATE,
            expirationTimestamp: ts5minsAfterNow
        })

Unfortunately the order that gets to cTrader is Good Till Canceled.
I've also tried MidaOrderTimeInForce.FILL_OR_KILL and it's the same, the order arrives as Good Till Canceled.

Maybe this is not yet implemented?

Historic Data

Is there a way to get historic data offered by the broker/exchange, let's say the 5m chart from a month back?

[FEATURE] getSymbolPeriods on the past

Many exchanges (Binance) offer to retrieve OHLC data far in the past (from the origin of the market), also in 1 minute time frame.

It would be handy to be able to do this with "getSymbolPeriods".

On documentation:

getSymbolPeriods (symbol: string, timeframe: number): Promise<MidaPeriod[]>;

Maybe can be :

getSymbolPeriods (symbol: string, timeframe: number, from: number, to: number): Promise<MidaPeriod[]>;

Live account info

Is there any way to get live account info?
EventEmitter or websocket like?
When an order is executed in cTrader for instance to get the event in Mida.

Create "connect" and "disconnect" events

Currently there is no way to know if a trading application has been disconnected from the trading platform.
We could introduce the following events on trading accounts

  • disconnect fired when the trading account socket is disconnected
  • connect fired when the trading account is reconnected

Including the following hooks for trading systems

  • onDisconnect
  • onConnect

Further design details should be discussed here

objects are null in console.log

This is a funny thing I've noticed in different places.
Might be the fact that I have your library in Nrwl NX, or maybe have an older node version?

  account.on("order", (event) => {
      const order = event.descriptor.order;
          console.log(order);
  });

console.log outputs CTraderOrder {} when I place an order.
But if I go for instance console.log(order.id, order.direction); i get what is there.

How is this possible? I did not see anything like this ever. :D

I am unable to login to ctrader account using my credentials

I am unable to get my ctrader user account getting through login using MIDA API, I tried a couple of such accounts but it's still not getting me through it. Its working fine for last two months, but suddenly stopped working yesterday May 25, 2023.

const clientId = '';
const clientSecret = '
';
const accessToken = '';
const accountId = '
';

const account = await login("cTrader", {
clientId: clientId,
clientSecret: clientSecret,
accessToken: accessToken,
accountId: accountId,
});

Here is the version I am using.
"devDependencies": {
"@reiryoku/mida": "^2023.1.2",

And here is the error.

Error
at CTraderApplication.loginTradingAccount (D:\code\repos\Freedom.Trading\Freedom.Trading\Freedom.Trading.NextGen\Freedom.Trading.Mida\node_modules@reiryoku\mida\build\src\platforms\ctrader\CTraderApplication.js:69:19)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async CTrader.login (D:\code\repos\Freedom.Trading\Freedom.Trading\Freedom.Trading.NextGen\Freedom.Trading.Mida\node_modules@reiryoku\mida\build\src\platforms\ctrader\CTrader.js:34:32)


Edited by @Vasile-Peste to censor credentials

.toNumber() for MidaDecimal

I think MidaDecimal is a very good idea.
But I think it needs a simple method .toNumber() that should either return undefined if the initial value is undefined or number if there is a value.
For now I convert it to a string and then digest it with bignumber.js as I avoid doing Number(midaDecimal)

Mida login on AWS lambda

Hi, I've successfully managed to run Mida login on my computer and different VMs.

Nevertheless, trying it on AWS Lambda I get this error:

ERROR	TypeError: Cannot read properties of null (reading 'build')
    at CTraderProtobufReader.build (/var/task/index.js:14681:17)
    at new CTraderConnection (/var/task/index.js:15028:78)
    at new CTraderApplication (/var/task/index.js:17078:74)
    at Function.<anonymous> (/var/task/index.js:17163:171)
    at Generator. next (<anonymous>)
    at /var/task/index.js:17031:71
    at new Promise (<anonymous>)
    at __awaiter (/var/task/index.js:17013:14)
    at Function.create (/var/task/index.js:17162:16)
    at CTrader.<anonymous> (/var/task/index.js:17222:84)

Is there any installation guide for AWS Lambda?
Or at least is it possible to obtain a more understandable error?

Historical Trades and Orders

Is it possible to get a list of trades and orders older than the most recent ones, currently obtained by doing myAccount.getOrders or myAccount.getTrades?

Closed Position Detail

I want to retrieve the net profit and possibly the account balance of an executed trade.

According to the cTrader documentation, they should be contained in the protooaclosepositiondetail object contained in a trade.

Nevertheless, this object is not there in this plugin.

Closed Position Detail

I want to retrieve the net profit and possibly the account balance of an executed trade.

According to the documentation, I should find them in the protooaclosepositiondetail object contained in a trade.

Nevertheless, I haven't found a way to get this information.

The cTrader getOrders function return only 5 entries

With the latest Mida version 2023.1.1 the getOrders or the getTrades functions return only the latest 5 results.
This is not what was happening when I was using the CTraderPlugin.

Is it possible to have more results? Or even better to specify the period for the getOrders or the getTrades.

Mida.login error makes object undefined

I found out that when I call Mida.login() twice or multiple times on the cTrader account I get an error like:

{
  payloadType: 'PROTO_OA_ERROR_RES',
  ctidTraderAccountId: '***',
  errorCode: 'ALREADY_LOGGED_IN',
  description: 'Trading account is already authorized in this channel',
  maintenanceEndTimestamp: null,
  clientMsgId: '84c939f0-ee05-11ec-8fc5-a50cce82f4dc'
}

Code to exemplify:

let account = await  Mida.login("cTrader", {...}); //good
account = await  Mida.login("cTrader", {...}); //error
account = await  Mida.login("cTrader", {...}); //same error

At this point cTrader knows it's a connection but the account object is undefined.
I would expect that even with this error message the original/first object from the first login to be a functional connection still.
For some reason it's not. Even if I call it multiple times I get the same error.
You can even try like:

const account1 = await  Mida.login("cTrader", {...}); //good
const account2 = await  Mida.login("cTrader", {...}); //error
const account3 = await  Mida.login("cTrader", {...}); //same error

The initial account is undefined after the second login that logs the error.

Create fallback symbols

Symbols may not be equal across all trading platforms, for example the Frankfurt 40 Index is represented as DAX40, DE40 or just GER40 depending on the trading platform.

This means that switching trading account could result in potential compatibility issues and the mission of Mida is to enforce platform-neutrality.

A potential solution would be adding the possibility to define fallback symbols for every operation that requires a symbol.
For example

const order = await myAccount.placeOrder({
    symbol: "DAX40|GER40|DE40`,
    // ...
});

ProtoOAGetTickDataReq does not work

anyone know how to get this one working?
ProtoOAGetTickDataReq

https://help.ctrader.com/open-api/messages/#protooagettickdatareq

this.#connection
      .sendCommand('ProtoOAGetTickDataReq', {
        ctidTraderAccountId: this.#account.brokerAccountId,
        symbolId: '41',
        type: 1,
        fromTimestamp: new Date('2022-12-12T11:00:00Z').getTime(),
        toTimestamp: new Date('2022-12-12T12:00:00Z').getTime(),
      })

This is my code. It just does not return anything. Does this mean its actually not supported? Or does it depend on the broker?

it would be good to have this method added to the class as well

expirationDate is undefined

I create order next way:

    const myOrder = await myAccount.placeOrder({
        symbol: 'EURUSD', 
        direction: MidaOrderDirection.BUY,
        volume: 0.1,
        limit:1.078,
        protection: {
            stopLoss: 1.075, 
            takeProfit: 1.083, 
        },
        expirationDate: date().addMinutes(5),
    });

It doesn't create expirationDate property
console.log(myOrder.expirationDate); //undefined

  1. I try put inside expirationDate different values using native JS, not only from @reiryoku/mida. It doesn't matter
  2. I use "^2023.5.0" version

Adding a custom id to a MidaTradingAccount

Is there a way to add a custom id to a MidaTradingAccount when using Mida.login()?

The MidaTradingAccount class does have an id property but it's set as read only so I can't assign any value to it. Is this intentional?

Last live candle

Is it possible to get the last LIVE candle for the 5m chart for instance from cTrader(Pepperstone)?
I understand that there is an event for getting the last closed candle, and also the tick data.
There is a way(not best) to create the last candle from the tick data in a 'live' form, but is something like this already available from the broker? Or what are your suggestions for needing to execute market orders that depend on the live candle(to compute indicators).

Thanks

H4 timeframe

Hi, there is a way to use H4 timeframe with the MidaTradingSystem ?

Because I have this issue when i run the MidaStradingSystem with H4 period (who is typed)

/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@reiryoku/mida-binance/src/core/platforms/binance-spot/BinanceSpotAccount.ts:719
            throw new Error("Unknown timeframe");
                  ^
Error: Unknown timeframe
    at normalizeTimeframe (/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@reiryoku/mida-binance/src/core/platforms/binance-spot/BinanceSpotAccount.ts:719:19)
    at BinanceSpotAccount._BinanceSpotAccount_onPeriodUpdate (/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@reiryoku/mida-binance/src/core/platforms/binance-spot/BinanceSpotAccount.ts:558:35)
    at /Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@reiryoku/mida-binance/src/core/platforms/binance-spot/BinanceSpotAccount.ts:495:145
    at ReconnectingWebSocket.w.onmessage (/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/[email protected]/node_modules/binance-api-node/dist/websocket.js:219:7)
    at WebSocket.ReconnectingWebSocket._handleMessage (/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/[email protected]/node_modules/reconnecting-websocket/dist/reconnecting-websocket-cjs.js:174:23)
    at WebSocket.onMessage (/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/[email protected]/node_modules/ws/lib/event-target.js:132:16)
    at WebSocket.emit (node:events:513:28)
    at WebSocket.emit (node:domain:489:12)
    at Receiver.receiverOnMessage (/Users/quiet/Documents/Perso/ichigram/node_modules/.pnpm/[email protected]/node_modules/ws/lib/websocket.js:1068:20)
    at Receiver.emit (node:events:513:28)

The mida system :

import { MidaTradingSystem, MidaTimeframe, } from "@reiryoku/mida";

export class SuperTradingSystem extends MidaTradingSystem {
    watched () {
        return {
            "BTCUSD": {
                watchTicks: true,
                watchPeriods: true,
                timeframes: [ MidaTimeframe.H1, MidaTimeframe.H4, ],
            },
        };
    }
    
    async configure () {
        // Called once per instance before the first startup
        // can be used as async constructor
    }
    
    async onTick (tick) {
        const { bid, ask, date, } = tick;
    }
    
    async onPeriodClose (period) {
        const [ open, high, low, close, ] = period.ohlc;
        
    }
}

Edit :

Found the issue : https://github.com/Reiryoku-Technologies/Mida-Binance/blob/6609378af251cc6f6ec084780bd6ec0f701c8487/src/core/platforms/binance-spot/BinanceSpotAccount.ts#L683

There is no "H4" time frame.

Second edit :

https://github.com/Reiryoku-Technologies/Mida-Binance/pull/5

composePeriods() sets incorrect values

I've just checked now, but with the latest Mida composePeriods() sets the high and low equal to the open.
It used to work well. Maybe the issue is since the MidaDecimal update?

Mida events subscription fault tolerance

I have been running Mida to watch the ticks on a cTrader account for some time.
At some point it just stops receiving data.
Are the connections to cTrader fault tolerant? In case of internet dropping or any other form of disconnect I mean.
I did not see any error being thrown or logged.
I'm thinking it may also be a thing where cTrader disconnects all connections?
Funny fact is I had 2 open connections from 2 projects watching the same data on the same PC. And they were both disconnected at the same time today at around 12:20 GMT.

Mida instances

IMHO this is a must as there is no way with Mida right now to trade multiple accounts from the same app.

This would be very cool:

const accountBinance = new Mida("Binance/Spot",{...});
await accountBinance.login();
console.log(await accountBinance.getBalance());

const accountCTraderLive =  new Mida("cTrader",{...});
await accountCTraderLive.login();
console.log(await accountCTraderLive.getBalance());

const accountCTraderDemo =  new Mida("cTrader",{...});
await accountCTraderDemo.login();
console.log(await accountCTraderDemo.getBalance());

Would this be possible as a future development?

Market Components example

First of all - thank you for this awesome project!

"Trading systems are used under the hood to regulate and execute market components. It's recommended to use the Market Component API over the Trading System API as it allows to quickly develop and maintain an idea in a declarative way."

Second - since Market Components are preferred over Trading System API , could your provide a full example of a running service with this structure?

[FEATURE] CCXT Bridge

Hi, thanks for this amazing job.
Why not do a bridge with CCXT library to allow the use of all the crypto exchanges they support?

ERROR IN PRODUCTION

Hello guy, how are you?

Can you help me?

Method marketWatcher.on("tick", (event:).... not working in production, not reveive information symbols.

`placeOrder` message `Unknown payload type 2142`

Hi there,

I'm trying to use your package. So far everything has worked: connecting, getting some data from my demo account, etc.
Now when it comes to myAccount.placeOrder, as stated in the subject, I just get this weird message Unknown payload type 2142 and my script stops continuing.

Would you know what the issue is? Thanks!

Add a function / method that helps calculate take profit and stop loss price points on all symbols.

Stop Loss and Take Profit calculation for all symbols.

Have different functions to calculate stop loss and take profit that takes in different arguments.

Stop Loss Function example:

function getStoplossPricePoint(symbol,amountToRisk,lotSize) => {stop_loss_number_of_pips,stop_loss_price_point}

function getStoplossPricePoint(symbol,numberOfPipsToRisk,amountToRisk)=>{lot_size_to_use,stop_loss_price_point}

function getStoplossPricePoint(symbol,numberOfPipsToRisk,lotSize)=>{amountToRisk,stop_loss_price_point}

Take PROFIT Function example:

function getTakeProfitPricePoint(symbol,amountToTakeAsProfit,lotSize) => {take_profit_number_of_pips,take_profit_price_point}

function getTakeProfitPricePoint(symbol,take_profit_number_of_pips)=>{take_profit_price_point,amount_to_take_as_profit}

function getTakeProfitPricePoint(symbol,amountToTakeAsProfit,take_profit_number_of_pips)=>{take_profit_price_point,amount_to_take_as_profit,lot_size_to_use}

ERRO EXE FUNCTION MIDA.LOGIN

Hello guys, I have error when try login.

PS C:\Users\es04707\Documents\ctrader> node index.js
C:\Users\es04707\Documents\ctrader\node_modules@reiryoku\mida\build\src\core\Mida.js:18
const pluginId = plugin?.id;
^

SyntaxError: Unexpected token '.'
at wrapSafe (internal/modules/cjs/loader.js:931:16)
at Module._compile (internal/modules/cjs/loader.js:979:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
at Module.load (internal/modules/cjs/loader.js:879:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Module.require (internal/modules/cjs/loader.js:903:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object. (C:\Users\es04707\Documents\ctrader\node_modules@reiryoku\mida\build\entry\node\main.js:17:14)
at Module._compile (internal/modules/cjs/loader.js:1015:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
PS C:\Users\es04707\Documents\ctrader>

Can you help me?

Profit calculation on currency pairs with JPY as the quote currency is not accurate.

Calling the method getUnrealizedGrossProfit() on a position with a currency pair that has JPY as the quote currency gives an inaccurate profit value, even after adding commission gotten from the method call getUnrealizedGrossProfit() to the unrealizedGrossProfitValue.

ENVIRONMENT

##Broker : Pepperstone

##Trading Software: cTrader

##Account type: DEMO

##Libraries: Mida, Mida-ctrader

HOW TO REPRODUCE THE ERROR

  1. Make sure there is an open position with JPY as the quote currency e.g EURJPY, USDJPY e.tc
  2. Get the open positions.
  3. Loop through the open positions and calculate the unrealizedProfit/loss

WHAT TO NOTE

  1. The profit/loss calculation for other pairs is accurate
  2. The profit/loss calculation for currency pairs with JPY as the quote currency is inaccurat.

const unrealizedCommision = await position.getUnrealizedCommission();
const unrealizedGrossProfit = await position.getUnrealizedGrossProfit();
const profit = unrealizedGrossProfit-Math.abs(unrealizedCommision) ;

Backtest could be improved

Ticks and Periods

The actual backtest engine doesn't looks like to simulate real market data, what I'd like to have is something that can replicate as much as possible what happens in live, so have an alternation of ticks and periods, in the actual backtest instead when running elapseTime we have that all ticks in are fired before all periods https://github.com/Reiryoku-Technologies/Mida/blob/master/src/playground/MidaPlaygroundEngine.ts#L287-L328
This for me is wrong because in my strategy I want to do things when period is closed and other things when a new tick comes. The solution I propose is to use the property MidaPeriod#ticks to simulate better the market.

    async #processPeriods (periods: MidaPeriod[]): Promise<MidaTick[]> {
        const elapsedTicks: MidaTick[] = [];

        periods.sort((a: MidaPeriod, b: MidaPeriod): number => a.startDate.timestamp - b.startDate.timestamp);

        for (const period of periods) {
            let ticks: MidaTick[] | undefined = period.ticks;
            if (ticks == undefined || ticks.length == 0)
                ticks = [ tickFromPeriod(period, "close"), ];

            await this.#processTicks(ticks);
            await this.#onPeriodUpdate(period);

            /*if (period.isClosed) {
                await this.#onPeriodClose(period);
            }*/

            elapsedTicks.push(...ticks);
        }

        return elapsedTicks;
    }

In this way I can create from csv files a MidaPeriod array in which each period have its own ticks array and they are simulated almost exactly as live market (if a period doesn't have any tick fall back to the previous method).

Trading System deadlock

Another issue I've found in the backtest engine is this call await this.#onPeriodClose(period); (which I've commented). The MidaTradingSystem subscribe only to tick and period-update of the market watcher and not the period-close, but instead the close period callback of the system is fired by the system itself: https://github.com/Reiryoku-Technologies/Mida/blob/master/src/core/systems/MidaTradingSystem.ts#L448-L463

If the engine uses waitFeedConfirmation option it stuck on the first period because I've no way to proceed with the next feed. I've commented out just to get it working for me, I don't know which could be the best solution, please tell me :)

Missing import { marketComponent, }

Hi

Im reading the docs:

https://github.com/Reiryoku-Technologies/Mida#market-components

and

https://www.mida.org/posts/reactive-programming-in-financial-markets/#component-structure

But it doesn't seem to be implemented in the 2022.5.0 release - am I missing something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.