Topics
14 Mar 2021, 17:53
 1806
 17
19 Jan 2021, 18:33
 1004
 4
Replies

prosteel1
23 Oct 2020, 18:49

RE:

Awesome! I've been trying to figure this out lately, Thanks! I think we should join your writing code with my multitimeframe get more history code :)  I tried running mine on 4GB ram using Tick 10, Minute etc and it ran out of memory, 32Gb ram worked eventually. I'm considering storing historic data locally so if the data is available locally it wont try to load more history. Could help those without 32GB ram to have access to all the history just by sharing files or running the bot multiple times :)

It looks like Tick, minute etc (lower timeframe) data is only available for a certain time before it is no longer available. So having a way to store what is available now could be useful in the future - especially if it was part of a bot starting up.

 


@prosteel1

prosteel1
23 Oct 2020, 18:27

While I don't do indicators, I run the same code on multiple timeframes using an array of integers Frames[], I iterate through that array to have multiple timeframes. And I repeatedly run "Bars series = MarketData.GetBars(Frames[a]);" to get the latest data in that timeframe - mostly to check if there is a new bar or a new high or low. 

Once the bot gets past the On Start() method the 0 bar being the most distant bar is always the same - this becomes the datum on that timeframe and is the same always (unless the bot is running in realtime and you zoom out or scroll back).

When I started writing my code I named the timeframes using different names like Bars series0 = MarketData.GetBars(Frames[0]), Bars series1 = MarketData.GetBars(Frames[1]), Bars series2 = MarketData.GetBars(Frames[2]), but then needed multiple copies of my code for series0, series1, series2 etc. My code got a bit long and I couldn't figure out how to index the series0 as series[0] (although that almost makes sense atm lol). My solution isn't great but it works for me so far.

I use the Frames integer as an index to update the values on various timeframes. Hope this helps :)

Fell free to ask more questions :)

You code might be better, but just for funzies Day of week can also be an int like this: 

int day = (int)Server.Time.DayOfWeek;

Same thing your doing I think just using the int of the day of week rather than the name.

 

 

 


@prosteel1

prosteel1
23 Oct 2020, 17:23

RE: RE:

The founder of Accord.Net has left the project. It is listed as having 9 developers and the project seems to be in a coma on life support.

While it does have good documentation for some things, without a lot of testing and fixing going on, the code is stuck where it is for a long time.

For Example. I'm looking at Genetics (similar to the cTrader Optimization). But if I find a bug I'll have to fix it myself which I likely don't have the ability to do. 

cTrader Optimisation doesn't support multiple timeframes - thus my need for machine learning that can do multiple timeframes.

 

On the flipside, ML.Net is in active development but does have bugs reported which are fixed quite quickly.

 

There is a danger with using a project which may never be supported, as if or when there is a bug or a required feature addition it may never come.

 

I would like to see the upcoming cTrader version 4 support ML.NET through the upgrade of cTrader from .NET 4.0 client framework to .NET Core. I can see that as being a long term support solution that would benefit cTrader and it's users greatly.

In the meantime I'll be looking to use Accord knowing that I might come up against a brick wall but hoping that I don't :).


@prosteel1

prosteel1
22 Oct 2020, 15:25

RE: RE:

ctid2032775 said:

Hi,

I'm using machine learning in one of my cBots for training a model (C4.5 decision tree), identifying the accuracy (TP, FP, TN, FN) and making predictions before opening a position.

It's working fine but I'm using the Accord.NET framework instead of ML.NET. With this library everything can be done directly in a cBot without writing a csv file and develop an additional "stand alone" application for the machine learning part!

There are a lot of documents and code examples available and the modules are really well explained. You can find all information under Accord.Net Framework.

BR,
Christian

 

Looks great, thanks heaps!


@prosteel1

prosteel1
21 Oct 2020, 13:18

RE: RE:

genappsforex said:

there is a problem with the framework (see discussions on netstandard 2.0 in this forum)

 

Thanks,

            I've been trying for the past 3 days to get the netstandard2.0 based ML.NET running in a calgo file in Visual studio. Dispite changing the target framework and target platform I haven't succeeded.

@PanagiotisCharalampous mentioned cTrader 4.0 would be upgraded to  .NetCore, would that upgrade allow it to work?


@prosteel1

prosteel1
18 Oct 2020, 19:03

RE: RE:

firemyst said:

caglar_G said:

What is the best method for initating a wait for a bot, example: The bot made a trade and closed, after closing you want it to wait for an x amount of time. Is threading.sleep sufficient?

I'd rather not use threading.sleep as it basically suspends the bot for a set amount of time, I might want the bot to do some calulations in the meantime. Is there an alternative to threading.sleep to achieve something like that? Thanks!  

You have multiple options depending on how you want to wait.

Example #1: you want to wait until a new bar is opened. That's easy. Just create a bool flag such as "closedThisBar". In your Positions_Closed event method, set "closedThisBar" to true. In the OnBar method, set "closedThisBar" to false. Then whenever you're wanting to open a position, check the flag before opening the position.

eg, if (!closedThisBar) { OpenPosition.... }

 

Example #2: you want to wait x-minutes/second. That's a bit more involved, but not difficult. Use the timer. In the timer event method, when the number of seconds/minutes has passed, again set a flag to indicate it's ok to open positions again.

 

Example #3: you want to wait x-ticks. Similar to #1 except you also need a variable to count the number of ticks. When a position is closed, reset your tick count to zero. When your tick count reaches your set threshold, set the boolean flag to true so you can open positions again.

 

That's just 3 ways off the top of my head.

Hope it helps :-)

I like your Example #1 solution, as waiting for the current bar to close before opening a new trade if the last trade closed in loss is something I've been wanting to impliment, this is how I would do it that can run OnTick and use a different timeframe to the chart timeframe.

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter("Timeframe0", DefaultValue = "Hour4")]
        public TimeFrame tf0 { get; set; }
        int i = 0;
        protected override void OnStart()
        {
            Positions.Closed += PositionsOnClosed;
        }

        protected override void OnTick()
        {
            // Insert code to only run after count is larger than the count when the last position was closed
            Bars series = MarketData.GetBars(tf0);
            if (i == 0 || i < series.Count - 1)
            {
                // Insert normal Trading code
                Print("series.Count - 1 = " + (series.Count - 1));
            }
            else
            {
                // Insert other Calculations
            }
        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            // Get Bars on the specified timeframe then write the current bar to i
            Bars series = MarketData.GetBars(tf0);
            int i = series.Count - 1;
        }
        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

 


@prosteel1

prosteel1
18 Oct 2020, 16:54

RE:

caglar_G said:

What is the best method for initating a wait for a bot, example: The bot made a trade and closed, after closing you want it to wait for an x amount of time. Is threading.sleep sufficient?

I'd rather not use threading.sleep as it basically suspends the bot for a set amount of time, I might want the bot to do some calulations in the meantime. Is there an alternative to threading.sleep to achieve something like that? Thanks!  

I have been thinking about this too.

I'm not sure what the best way is, but in the below code you could re-write AnalysisStartDate when a trade closed and use Add.Minutes or similar to the order expiry concept. 

Positions.Closed += PositionsOnClosed; could be used in this way as it calls the method when a position is closed.

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter(DefaultValue = 0)]
        public int Minute { get; set; }
        [Parameter(DefaultValue = 0)]
        public int Hour { get; set; }
        [Parameter(DefaultValue = 18)]
        public int Day { get; set; }
        [Parameter(DefaultValue = 10)]
        public int Month { get; set; }
        [Parameter(DefaultValue = 2020)]
        public int Year { get; set; }

        DateTime AnalysisStartDate;

        protected override void OnStart()
        {
            AnalysisStartDate = new DateTime(Year, Month, Day, Hour, Minute, 0);
            Positions.Closed += PositionsOnClosed;
        }

        protected override void OnTick()
        {
            // Insert code to only run after Server.Time.Date >= AnalysisStartDate
            if (Server.Time.Date >= AnalysisStartDate)
            {
                // Insert normal Trading code
            }
            else
            {
                // Insert other Calculations
            }
        }
         private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            // Re-write AnalysisStartDate with extra delay
        }
    }
}

 


@prosteel1

prosteel1
10 Jul 2020, 22:29

RE: RE: RE: RE:

I’ve been testing this and seems good to manage memory.

I’ve setup a loadmorehistory routine that gets the date of the first bar on the highest timeframe and then loads more bars on lower timeframes.

I haven’t had to use the Ticks as you mentioned as yet, rather, I use bars of Tick10 etc. using a workaround I posed in this linked post below.

When I set the higher timeframe as 4 hour it went back almost a year, then the other 6 timeframes down to Tick5 loaded history back to there which resulted in 1,700,000+ bars on Tick 5 and 1 minute and yes it took a very long time to load and analyse on i7 with 32GB ram haha

 


@prosteel1

prosteel1
27 Jun 2020, 16:07

RE:

Delphima said:

Hello,

I want to get last bar's high and low prices in my cBots, but the print always gives the same value. 

Can anyone help to have a look, where is the problem?

Thanks,

Lei


using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class RayLei : Robot
    {
        protected override void OnBar()
        {
            Print("LastHigh: " + Bars.LastBar.High + " LastLow: " + Bars.LastBar.Low);
        }
    }
}

The issue is that the OnBar() is being triggered on the open of a new bar - so the High and Low of the last bar is actually the current just opened bar, so the high and low is the same, as it just opened 1 tick ago and it is giving the high and low of the bid price.

When I started, I tried using Bars.HighPrices.Last(1) but found it too confusing to work with when accessing previous bars as the index number of previous bars keeps changing. I ditched Bars.HighPrices.Last(1) which has a constantly moving index where the most recient bar is always 1, in favor of the Bars.HighPrices[series.Count - 2] where the oldest bar is 1 and the most recient bar starts at 2000 or so and keeps incrementing in it's count as each new bar opens.

 

I run a cbot that can work on multiple timeframes and each time I call "Bars series = MarketData.GetBars(TimeFrame);" I can use an index of "series.Count - 2" to get the index of the PREVIOUS Bar on that timeframe that just closed while the index 1 bar is always the same most historical bar that only changes if I scroll back and make it load more bars. This gives me a fixed Datum.

 

I think it is the High and low of the previous bar that you want and personally I find it easier to have an origin (Datum) bar with an index of 1 as the most historical bar and each new bar increments by one.

 

It may not be as confusing in your cbot, but Bars.HighPrices.Last(1) almost did my head in when I started and almost gave up thinking what I wanted to do wasn't possible - until I found the way I currently use lol.

Basic Example:

        protected override void OnBar()
        {
            Print("Count - 2 = " + (Bars.Count - 2) + ", Previous Bar High: " + Bars.HighPrices[Bars.Count - 2] + ", Previous Bar Low: " + Bars.LowPrices[Bars.Count - 2]);
        }

Multi Timeframe example:

protected override void OnBar()
{
       Bars series = MarketData.GetBars(TimeFrame);
       Print("Count - 2 = " + (series.Count - 2) + ", Previous Bar High: " + series.HighPrices[series.Count - 2] + ", Previous Bar Low: " + series.LowPrices[series.Count - 2]);
}


@prosteel1

prosteel1
27 Jun 2020, 13:21

RE: RE:

ctid2032775 said:

PanagiotisCharalampous said:

Hi Christian,

Unfortunately there is no feature for automatic optimization at the moment neither we have plans for this in the near future. If you need this, it is something you will need to develop yourself.

Best Regards,

Panagiotis 

Join us on Telegram


 

Hi,

I made it to develop a module for "automatic" optimization but have a quick question to finish it...

Right now this module reads historic data from a text file. This file is created by running a (small) cBot in backtesting mode that just gets the data (OnTick/OnBar) and writes it into the file. This requires some manual steps and to not loose any data (i. e. missing some ticks/bars) this can only be done during weekends!

I would like to fetch the data (OHLC, Ask, Bid) for a specific time frame (e. g. last 2 years) every time the cBot is started (OnStart) and run the optimization with this historic data - is there a way to realize this (maybe with FIX API or Open API)? Can you provide some code snippets and/or examples where this was already done?

Many thanks for your support.

BR,
Christian

I use a for loop OnStart to cycle through each bar from the current bar count back to count = 1. There is also a newish  'Bars.LoadMoreHistory' command to get a specified number of more bars. OnTick I check for a new Bar and I run it again but only go back 2 bars.  I think this is what you are looking for as the data available to Backtesting lags a day, whereas this accesses the live data :) Current bar data can be accessed using Bars.LastBar.Low etc and current bid/ask using Symbol.Bid and Symbol.Ask.

I run OnTick so I can check for the price reaching take profit 1 price to close half the position and to move the stoploss to entry and checking that the Symbol.Ask is not above the short stoploss when placing an order (as that prevents the stoploss from being set), etc etc.

OnStart()

Bars series = MarketData.GetBars(frame);
int i = series.Count - 1;

BarLast = i - 2;
for (int ii = i - 2; ii >= 1; ii--)
{

      // Write OHLC Data

}

OnTick()

// Check for a new bar on specific timeframe

Bars series = MarketData.GetBars(frame);
if (series.Count - 1 > BarLast)
{

     for (int ii = i - 2; ii >= x; ii--)
     {

           // Write OHLC Data

     }

}

 

In regards to your question above "Part of the bot is a machine learning algorithm that is already existing in C# - I guess it's not a problem to include this in a cBot, right?", I am quite a noob but when I investigated this I think the answer was C# was not suitable so it would need to use another language suited to machine learning and so going through the FIX API would be required. Possibly making an API to connect the ML code to the C# code?


@prosteel1

prosteel1
27 Jun 2020, 12:51

RE: Brainstorming - Genetic Algorithms & Agile Development

It looks like the built in optimization might use something like the Quasispecies model of Genetic evolution. A simple wiki is: https://en.wikipedia.org/wiki/Quasispecies_model  and a much more advanced ieeexplore paper based on Quantum Physics is: https://ieeexplore.ieee.org/ielx7/6287639/8600701/08684946.pdf?tp=&arnumber=8684946&isnumber=8600701&ref=aHR0cHM6Ly9pZWVleHBsb3JlLmllZWUub3JnL2RvY3VtZW50Lzg2ODQ5NDY=

 

I haven't got to implimenting it yet, however I'm hoping Eigenvalues could be calculated using a matrix determinant. 

The reason I am looking at this Eigenvalue concept is that charts are created by short term and longer term supports and resistance that have a probability of hitting a take profit. The most fit species would be the shorter term that would have it's probability of reaching it's take profit increased when it's resistance or support are broken and when it hits it's take profit it would die out due to 'error catastrophe' (see the bottom of the wiki link), and allow longer term species to eventually take over. Ofcourse new species would be added as they are identified.

So rather than running optimizations to find the parameters, the matrix of species would be the parameters.

 

Agile software development looks like it has potential as it starts out knowing that it does not know the solution and so it is based on finding the solution.

 

If we could get the optimization code that spotware uses so we could impliment it ourselves that would likely be quite useful. The GetFittnessArgs implimentation should allow some access but perhaps during manual optimization only (haven't got that far yet).

 

 

 


@prosteel1

prosteel1
27 Jun 2020, 08:34

RE: RE:

virtuesoft said:

cvphuoc, here is an example of how you can use the code...

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Requests;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class ExampleRobot : Robot
    {
        [Parameter("Stop Loss", DefaultValue = 6.0)]
        public double StopLoss { get; set; }

        [Parameter("Commission in Pips", DefaultValue = 0.8)]
        public double CommissionPips { get; set; }

        [Parameter("Risk Percent", DefaultValue = 0.5, MinValue = 0.1, MaxValue = 5.0)]
        public double RiskPercent { get; set; }

        [Parameter("Reserve Funds", DefaultValue = 0)]
        public int ReserveFunds { get; set; }

        [Parameter("Max Volume", DefaultValue = 5000000)]
        public int MaxVolume { get; set; }

        private int _volume;

        protected override void OnStart()
        {
            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnBar()
        {
            CalculateVolume();
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }

        private void CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            _volume = (((int)exactVolume) / 100000) * 100000;

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (_volume > MaxVolume)
                _volume = MaxVolume;
        }
    }
}

 

Thanks for this @virtuesoft, I have found the Symbol.NormalizeVolumeInUnits will round to the lowest volume even if the exactVolume is smaller than the Symbol.VolumeInUnitsMin.

So I have added an extra check to return -1 which I then check for in the place order code. This prevents a trade of the minimum trade size if it would result in more than the allowed risk being used. An example of this is on a small account trading 50 barrels of XBRUSD when 1% risk is only 5 barrels.

private double CalculateVolume(double SL)
{
    // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
    double totalBalance = Account.Balance + ReserveFunds;

    // Calculate the total risk allowed per trade.
    double riskPerTrade = (totalBalance * RiskPercent) / 100;

    // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
    double totalPips = (SL / Symbol.PipSize) + ComissionPips + Symbol.Spread;

    // Calculate the exact volume to be traded.
    double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);
    if (exactVolume >= Symbol.VolumeInUnitsMin)
    {
        _volume = Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down);

        // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
        if (_volume > MaxVolume)
            _volume = MaxVolume;
    }
    else
    {
        _volume = -1;
        Print("Not enough Equity to place minimum trade, exactVolume " + exactVolume + " is not >= Symbol.VolumeInUnitsMin " + Symbol.VolumeInUnitsMin);
    }
    return _volume;
}

 


@prosteel1

prosteel1
05 Jul 2018, 20:04

I have that code working for sell orders but not for Buy orders.

It's strange that find has not been implemented, as without being able to find a position by it's label there is no way to manage orders of the same type for different purposes.

It is incredibly frustrating! The pc is going out the window soon :(

I guess this is why all the example bots create market orders and not pending orders lol.

Surely with a major release like 3.0 this is the perfect time to make dealing with pending orders as easy as positions. I can see the 'Label' written in the Orders payne of crtader GUI.

Correct me if I'm wrong but isn't this the purpose of an API?  The vote for this feature is about 6 years old from memory.

 

Can we get some support on this issue please Admin?


@prosteel1

prosteel1
04 Jul 2018, 18:04

Thanks Mate! Much appreciate it :)


@prosteel1