Replies

paolo.panicali
08 Sep 2022, 23:28

Thank you so much

Xammo said:

Hi Paolo

If you don't need the bells and whistles (or potentially disastrous known issues!) of 4.2 I'd suggest rolling back to 4.1 if you want the automate display to work properly - https://ctrader.com/forum/ctrader-support/38830?page=1#8 

Thank you Xammo, I could install 4.1 ver on the server and I hope everything will be ok. Seriously, you helped me a lot with this tip. Thank you ! 


@paolo.panicali

paolo.panicali
06 Sep 2022, 22:08

never mind I will open a ticket

thank you for your prompt response anyway


@paolo.panicali

paolo.panicali
12 Aug 2022, 15:11 ( Updated at: 21 Dec 2023, 09:22 )

an example

this is the Log tab output and the following is the actual today s history from the history tab.

Now you have the number of the trades taken today, happy ending.

Of course you also need to check for open positions...so it will be a foreach var position in Positions and check how many trades with a certain position.Label or position.SymbolName and with Today s entry time there are....

 

//trade a day, how many trades today?? august 2022

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 OneTradeADay : Robot
    {
        protected override void OnStart()
        {
            var LastTrades = History.OrderByDescending(iTrade => iTrade.EntryTime).Take(100).ToArray();

            int TradesToday = 0, TradesTodayThisSymbol = 0;

            for (int i = 0; i < LastTrades.Length; i++)
            {
                if (LastTrades[i].EntryTime.Day == Bars.OpenTimes.LastValue.Day && LastTrades[i].ClosingTime.Month == Bars.OpenTimes.LastValue.Month && LastTrades[i].ClosingTime.Year == Bars.OpenTimes.LastValue.Year)
                {
                    Print("Symbol : {0}  ClosingTime : {1}", LastTrades[i].SymbolName, LastTrades[i].ClosingTime);
                    TradesToday++;
                }
            }

            Print("---------------------------------------------------------------------------------------");

            for (int i = 0; i < LastTrades.Length; i++)
            {
                if (LastTrades[i].SymbolName == Symbol.Name && LastTrades[i].EntryTime.Day == Bars.OpenTimes.LastValue.Day && LastTrades[i].ClosingTime.Month == Bars.OpenTimes.LastValue.Month && LastTrades[i].ClosingTime.Year == Bars.OpenTimes.LastValue.Year)
                {
                    Print("Symbol : {0}  ClosingTime : {1}", LastTrades[i].SymbolName, LastTrades[i].ClosingTime);
                    TradesTodayThisSymbol++;
                }
            }
        }

    }
}


@paolo.panicali

paolo.panicali
12 Aug 2022, 14:37

Also, maybe you are going Async...

Also, probably you are placing Async trades and sometimes you have the new trade executed when the older is still open  ( so that the entry price is in Positions...), and some other times the execution is delayed for any reason and the older is already closed...

So you wanna be specially careful if you are going async.

 


@paolo.panicali

paolo.panicali
12 Aug 2022, 14:24

i ve seen your new post...

apparently you are getting a null value and the bot crashes as expected, the trade you are trying to get the Entry Price must be into the History then... :-)

I replicated the thing here and I get right the same error when there are no trades open...if I use History I get the value...

bye


@paolo.panicali

paolo.panicali
12 Aug 2022, 13:23 ( Updated at: 12 Aug 2022, 13:24 )

a little issue

Hi, well the problem with what Firemyst suggests is that if along the day for any reason you stop and restart the bot, the counter will go to zero, so for instance if the bot takes a trade in the morning and at noon you have to stop the bot, then in the afternoon when you restart the bot if it gets a signal it will take another trade.

Also, if you have more than one bot working but you only want to take one trade a day, well the counter will count one trade per bot, so that trades will be from 0-4 at least.

I would personally just check the History and Positions of the day,.

So if there are not open positions nor positions closed that had been opened today on this symbol or using this Bot(check using the label when you open a trade) or in total including all symbols and all bots active then I take a new trade whenever I get a valid signal.

Doing so if you have to stop and restart the bot or use multiple bots or the vps crashes or whatever you will always get one trade a day.

Hope that helps

 

https://ctrader.com/api/reference/history

 


@paolo.panicali

paolo.panicali
12 Aug 2022, 13:02

a possible reason

Hi Mongol, maybe this can help you, I just tell you what it seems to me and my personal opinion, not the Truth.

...that code recalls the EntryPrice of the oldest currently open position on any symbol.

A possible reason for the price not being "stable" can be that by the time you use that function the position is already closed so that you are picking the price of another position and maybe on another symbol ( the second oldest that now it is the oldest because the oldest had been closed so now it is in the History and not in Positions) , in that case you should call History instead of Positions and refer to the current symbol.

You may also want to specify the symbol name in order not to pick another symbol price, which also could be the cause.

For instance if you run a bot with this line of code on 3 symbols in three different instances or in the same instance, you will end up mixing up prices and will take the price of a symbol for another symbol.

Not only that, if the outcome of the line of code you show is null cause there are not open positions currently, you will get a null value or the bot will crash and forced to stop.

Bottom line, I personally always hard type or parametrize the symbol name to sort, find or close positions (otherwise I sort find or close positions of another instance or another bot, also remember to label correctly the positions you open, that is the easiest wat to pick an open trade) and if the price is unstable is most likely because the position you are trying to take the price had been closed or maybe you set a rolling time window which is excluding the first open position time.

Hope that help bye.

 


@paolo.panicali

paolo.panicali
05 Aug 2022, 00:36 ( Updated at: 21 Dec 2023, 09:22 )

Hi, I would leave 3 lines of code into the bot and let a Web App doing the job

Because you have a simple code which guarantees you compatibility (3 lines of code using net framework system library no nuget library) , not crashing prone, minimal workload for Ctrader (if anything goes wrong into your bot, it s over) , reusable (few lines to add to any bot) and you have some privacy because you are making the requests from a web application installed on an external server.(you can deploy the webapp on a VPS or using pages like pythonanywhere as you wish, they will get an IP that does not belong to you)

In this example the Bot will buy if yesterdays temperature is higher than 2 days ago temperature in a city you can choose, the Web app send a request to a free weather api  (www.weather something.com/api......"  to get the temperatures.

At the end of the day the trade is closed and a new one is opened. You can change the city using CityName parameter.

The bot passes the City name and the current date to the web app, so that it can work also on backtesting.

............................ 

protected override void OnBar()
        {
            Data_WebApp OutPutData = new Data_WebApp();
            OutPutData.CityName = City_Name;
            OutPutData.Date = Bars.OpenTimes.LastValue.ToString("yyyy-MM-dd");
            Print(OutPutData.Date);

            //THIS IS THE REQUEST
            var json = new JavaScriptSerializer().Serialize(OutPutData);
            var url = "http://127.0.0.1:5000/api";
            string response = new WebClient().UploadString(url, json);

            // If yesterday temperature in Paris was higher than 2 days ago then buy otherwise sell
            // close prev day trade
            if (Bars.OpenTimes.Last(1).Day == Bars.OpenTimes.LastValue.AddDays(-1).Day)
            {
                Closealltrades();

                if (Int32.Parse(response) == 1)
                {
                    ExecuteMarketOrder(TradeType.Buy, Symbol, 1000, "Buy" + Symbol.Name, 50, 75);
                }
                if (Int32.Parse(response) == 0)
                {
                    ExecuteMarketOrder(TradeType.Sell, Symbol, 1000, "Sell" + Symbol.Name, 50, 75);
                }
            }
        }

   public class Data_WebApp
        {
            public string CityName;
            public string Date;
        }

....................

then you deploy your webapp consuming a weather api in this case it is a free one, weather visual cross...

Hope this will help, bye.


@paolo.panicali

paolo.panicali
04 Aug 2022, 10:47 ( Updated at: 21 Dec 2023, 09:22 )

Hi this is a possible solution

// Custom Timeframe MA 

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class MA_MultiTimeframe : Indicator
    {
        public enum TimeFrame_Custom
        {
            Daily,
            One_Hour
        }

        [Parameter("TimeFrameCode", DefaultValue = TimeFrame_Custom.Daily)]
        public TimeFrame_Custom TimeFrameCode { get; set; }

        [Parameter("Fast MA period", DefaultValue = 5)]
        public int Fast_Ma_Period { get; set; }

        [Parameter("MA Type", DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MaType { get; set; }

        [Output("FastMA_Value", LineColor = "Red")]
        public IndicatorDataSeries FastMA_Value { get; set; }


        private TimeFrame MyTimeFrame;

        private Bars CustomTFSeries;

        private MovingAverage Fast_MA, Slow_MA;


        protected override void Initialize()
        {
            switch (TimeFrameCode)
            {
                case TimeFrame_Custom.Daily:
                    MyTimeFrame = TimeFrame.Daily;
                    break;

                case TimeFrame_Custom.One_Hour:
                    MyTimeFrame = TimeFrame.Hour;
                    break;

            }

            CustomTFSeries = MarketData.GetBars(MyTimeFrame);
            Fast_MA = Indicators.MovingAverage(CustomTFSeries.ClosePrices, Fast_Ma_Period, MaType);
        }

        public override void Calculate(int index)
        {
            var CustomIndex = CustomTFSeries.OpenTimes.GetIndexByTime(Bars[index].OpenTime);

            FastMA_Value[index] = Fast_MA.Result[CustomIndex - 1];
        }
    }
}

 

bye


@paolo.panicali

paolo.panicali
03 Aug 2022, 02:47

maybe this can help you

// Month Separator by ppanicali2022//last 12 month  separator

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.CentralEuropeanStandardTime, AccessRights = AccessRights.None)]
    public class MonthSeparator : Indicator
    {
        public override void Calculate(int index)
        {
            if (Bars.OpenTimes[index - 1].Month == Bars.OpenTimes[index].AddMonths(-1).Month && Bars.OpenTimes[index - 1] >= DateTime.Now.AddYears(-1))
            {
                Chart.DrawVerticalLine("MonthStart" + index, index, Color.Red);
                Chart.DrawText("MonthName" + index, DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(Bars.OpenTimes[index].Month), index, Bars.ClosePrices[index], Color.Green);
            }
        }
    }
}


@paolo.panicali

paolo.panicali
03 Aug 2022, 01:48

maybe it already exists , frankly I do not know

Hi Vivek maybe it already exists, I have no idea.

bye.


@paolo.panicali

paolo.panicali
02 Aug 2022, 19:01 ( Updated at: 21 Dec 2023, 09:22 )

also Symbol.VolumeInUnitsStep

Symbol.VolumeInUnitsStep returns 1 for indexes, 1000 for Forex, 50 for crude oil....you can use that to categorize a symbol

 Print(Symbol.VolumeInUnitsStep);

Bye

 


@paolo.panicali

paolo.panicali
02 Aug 2022, 18:40 ( Updated at: 21 Dec 2023, 09:22 )

This is the easiest way for me

Hi, indexes has numerical digits and less than 3 decimals, forex have minimum 3 decimals...there are some exceptions but you can start from here if you want... the Symbol interface can help...

Bye

 

// Symbol Recognizer by paolo panicali 2022
//indexes have numerical digits, forex has more than 2 decimals...

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SymbolRecognizerCtrader : Indicator
    {
        public override void Calculate(int index)
        {
            if (index == 0)
            {
                string SymbolName = Symbol.Name;
                int Counter = 0;
                int val;

                for (int i = 0; i < SymbolName.Length; i++)
                {
                    if (Char.IsDigit(SymbolName[i]))
                        Counter++;
                }

                if (Counter > 0)
                    Print("Hello, I am an Index and my name is " + Symbol.Name);

                if (Symbol.Digits >= 3)
                    Print("Hello, I am a Forex, my name is " + Symbol.Name);
            }
        }
    }
}


@paolo.panicali

paolo.panicali
01 Aug 2022, 17:17

And if you didn t remember to install Net 6 sdk and runtimes from the microsoft official page


@paolo.panicali

paolo.panicali
01 Aug 2022, 17:11 ( Updated at: 21 Dec 2023, 09:22 )

I updated to ctrader 4.3.9, the issue can be solved changing the Ctrader compiler as per a previous post on this forum

 


@paolo.panicali

paolo.panicali
31 Jul 2022, 19:57

Ctrader telegram channel

Hi I joined ctrader official telegram channel. Bye


@paolo.panicali

paolo.panicali
30 Jul 2022, 19:56 ( Updated at: 21 Dec 2023, 09:22 )

Drawdowns and RunUps of each trade in Ctrader and results saved to csv file in order to make further investigations on Python

Hi I just made this, the code has to be carefully checked but it seems to work fine.

The bot buys randomly, Do not use this in live trading, remember to switch to a demo account when testing.

I found out that the Run ups distribution is normal while the drawdown distribution is not. Somebody might tell us if I made a mistake or it s ok.

The robot write on a CSV file with the data of the trades, it needs  AccessRights = AccessRights.FileSystem if you do not want Ctrader to have access to your computer to save CSV file, you can remove the filewriter code and keep AccessRights = AccessRights.None

// Run Up and Draw Downs save to csv by paolo panicali july 2022

using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;


namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FileSystem)]
    public class DDRUCtrader : Robot
    {
        System.Random random = new System.Random();

        IndicatorDataSeries MaxDD_Eta;
        IndicatorDataSeries BarsInTradeSerie;
        IndicatorDataSeries MaxDD_Value;

        IndicatorDataSeries MaxRU_Eta;
        IndicatorDataSeries LossBarsInTradeSerie;
        IndicatorDataSeries MaxRU_Value;

        int DD_index = 0, RU_index = 0, counter = 0;
        double SL = 25, TP = 35;

        string filename;
        StreamWriter _fileWriter;

        protected override void OnStart()
        {
            Positions.Closed += PositionsOnClosed;
            MaxDD_Eta = CreateDataSeries();
            MaxDD_Value = CreateDataSeries();
            BarsInTradeSerie = CreateDataSeries();
            MaxRU_Eta = CreateDataSeries();
            LossBarsInTradeSerie = CreateDataSeries();
            MaxRU_Value = CreateDataSeries();
        }

        protected override void OnBar()
        {
            // prepare a csv file to store the results
            if (counter == 0)
            {
                filename = Symbol.Name + "_Trades" + ".csv";
                var filePath = Path.Combine("C:\\PATH", filename);
                _fileWriter = File.AppendText(filePath);
                _fileWriter.AutoFlush = true;
                _fileWriter.WriteLine("DateTime" + ";" + "EntryPrice" + ";" + "Close" + ";" + "RunUp" + ";" + "DrawDown" + ";" + "index" + ";" + "OutCome");
                counter = 1;
            }


            // BUY random hour from 1 to 20
            int HourRnd = random.Next(1, 20);
            if (HourRnd == Bars.OpenTimes.LastValue.Hour && Positions.Count() == 0)
            {
                ExecuteMarketOrder(TradeType.Buy, "EURUSD", 1000, "BUY RANDOM: " + Symbol.Name, SL, TP);
            }
        }


        protected override void OnStop()
        {
            int TotalProfitTrades = MaxDD_Eta.Count();
            MovingAverage DDETA_avg = Indicators.MovingAverage(MaxDD_Eta, TotalProfitTrades, MovingAverageType.Simple);
            Print("Average Draw Down Bars ETA: " + DDETA_avg.Result[TotalProfitTrades - 1]);


            MovingAverage DDValue_avg = Indicators.MovingAverage(MaxDD_Value, TotalProfitTrades, MovingAverageType.Simple);
            Print("Average Draw Down in Pips : " + DDValue_avg.Result[TotalProfitTrades - 1]);

            MovingAverage BarsInTrade_avg = Indicators.MovingAverage(BarsInTradeSerie, TotalProfitTrades, MovingAverageType.Simple);
            Print("Average Bars in Trade : " + BarsInTrade_avg.Result[TotalProfitTrades - 1]);

            ///
            int TotalLossTrades = MaxRU_Eta.Count();

            MovingAverage RUETA_avg = Indicators.MovingAverage(MaxRU_Eta, TotalLossTrades, MovingAverageType.Simple);
            Print("Average Run Up Bars ETA: " + RUETA_avg.Result[TotalLossTrades - 1]);

            MovingAverage RUValue_avg = Indicators.MovingAverage(MaxRU_Value, TotalLossTrades, MovingAverageType.Simple);
            Print("Average Run Up in Pips : " + RUValue_avg.Result[TotalLossTrades - 1]);

            MovingAverage LossBarsInTrade_avg = Indicators.MovingAverage(LossBarsInTradeSerie, TotalLossTrades, MovingAverageType.Simple);
            Print("Average Bars in Trade : " + LossBarsInTrade_avg.Result[TotalLossTrades - 1]);

            Print("Stop Loss Pips :" + SL + "  and Take profit Pips :" + TP);

            // Close the CSV file with raw data on trades
            _fileWriter.Close();
        }


        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            int EntryTime_position_index;
            // find entry bar index
            EntryTime_position_index = 0;
            DateTime EntryTime_position = args.Position.EntryTime;
            for (int i = 0; i < 1000; i++)
            {
                if (Bars.OpenTimes.Last(i) == EntryTime_position)
                {
                    EntryTime_position_index = i + 1;
                    break;
                }
            }

            // position properties
            double EntryPrice_position = args.Position.EntryPrice;
            double StopLoss_position = args.Position.StopLoss.Value;
            double TakeProfit_position = args.Position.TakeProfit.Value;
            double ClosingPrice_position = Bars.ClosePrices.LastValue;
            //better calculating the closing price from the position profit

            // drawdown data for positions went in profit

            if (args.Position.NetProfit > 0)
            {
                Print("Position Closed In Profit :");
                double Position_Min = Bars.LowPrices.Minimum(EntryTime_position_index);
                //double Position_Max = Bars.HighPrices.Maximum(EntryTime_position_index);

                double Position_DD = Math.Round((EntryPrice_position - Position_Min) / Symbol.PipSize);
                //double Position_RU = Position_Max - EntryPrice_position;
                // Draw Down Index
                int MaxDD_position_index = 0;

                for (int i = 0; i < 1000; i++)
                {
                    if (Bars.LowPrices.Last(i) == Position_Min)
                    {
                        MaxDD_position_index = i;
                        break;
                    }
                }
                int MaxDD_ETA_index = EntryTime_position_index - MaxDD_position_index;
                MaxDD_Eta[DD_index] = MaxDD_ETA_index;
                MaxDD_Value[DD_index] = Position_DD;
                BarsInTradeSerie[DD_index] = EntryTime_position_index;

                Print("Bars in Trade : " + BarsInTradeSerie[DD_index] + " Max DD Bar index : " + MaxDD_Eta[DD_index] + "  DD pips  " + MaxDD_Value[DD_index]);

                if (counter == 1)
                {
                    _fileWriter.WriteLine(args.Position.EntryTime + ";" + args.Position.EntryPrice + ";" + Bars.ClosePrices.LastValue + ";" + " " + ";" + MaxDD_Value[DD_index] + ";" + MaxDD_Eta[DD_index] + ";" + "PROFIT");
                }
                DD_index = DD_index + 1;
            }

            // drawdown data for positions went in profit
            if (args.Position.NetProfit < 0)
            {
                Print("Position Closed In LOSS :");
                double Position_Max = Bars.HighPrices.Maximum(EntryTime_position_index);
                double Position_RU = Math.Round((Position_Max - EntryPrice_position) / Symbol.PipSize);
                // Draw Down Index
                int MaxRU_position_index = 0;

                for (int i = 0; i < 1000; i++)
                {
                    if (Bars.HighPrices.Last(i) == Position_Max)
                    {
                        MaxRU_position_index = i;
                        break;
                    }
                }
                int MaxRU_ETA_index = EntryTime_position_index - MaxRU_position_index;
                MaxRU_Eta[RU_index] = MaxRU_ETA_index;
                MaxRU_Value[RU_index] = Position_RU;
                LossBarsInTradeSerie[RU_index] = EntryTime_position_index;
                if (counter == 1)
                {
                    _fileWriter.WriteLine(args.Position.EntryTime + ";" + args.Position.EntryPrice + ";" + Bars.ClosePrices.LastValue + ";" + MaxRU_Value[RU_index] + ";" + " " + ";" + MaxRU_Eta[RU_index] + ";" + "LOSS");
                }
                Print("Bars in Trade : " + LossBarsInTradeSerie[RU_index] + " Max RU Bar index : " + MaxRU_Eta[RU_index] + "  RU pips  " + MaxRU_Value[RU_index]);
                RU_index = RU_index + 1;

            }
        }
    }
}

 

in order to import in python and see the distribution here is the code

# -*- coding: utf-8 -*-
"""
Created on Sat Jul 30 17:51:39 2022

@author: Paolo Panicali
"""

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

Symbol='EURUSD'
Trades=99999

DataPath='C:\\PATH\\'+Symbol +'_Trades.csv'

#carica dati dal file in df
path_load=DataPath
df = pd.read_csv(path_load,sep=";",decimal=",", engine='python')

df_profit=df[df['OutCome'] =='PROFIT'] 
df_loss=df[df['OutCome'] =='LOSS'] 

df_profit["DrawDown"] = pd.to_numeric(df_profit["DrawDown"])
df_loss["RunUp"] = pd.to_numeric(df_loss["RunUp"])

DDown = df_profit['DrawDown']
RUp=df_loss['RunUp']

## RUN THIS FOR DRAWDOWNS
plt.hist(DDown,alpha=0.5,bins=np.arange(0,40,1),color='blue', label='Draw Down')
plt.margins(x=0, y=0)
plt.gca().set(title=Symbol+' Draw Down Distribution', ylabel='Total Profit Trades: '+str(len(df_profit)));
plt.ylim(0,40)
plt.legend();

## RUND THIS FOR RUNUPS
plt.hist(RUp,alpha=0.5,bins=np.arange(0,40,1),color='red', label='Run Up')
plt.margins(x=0, y=0)
plt.gca().set(title=Symbol+' Run Up Distribution', ylabel='Total Loss Trades: '+str(len(df_profit)));
plt.ylim(0,40)
plt.legend();

 

Hope this will help, the code should be double checked and cleaned so please if you find any error or improvement to be made let me know.

Bye.


@paolo.panicali

paolo.panicali
30 Jul 2022, 15:38

Build succeded...Quartz 2.6.2

I necessarily have to use a net version >4 for a project, so what I did was a console App in visual studio and made the Ctrader Bot or Indicator executing it and catching the output value/s:

                string filename = "C:\\Yourpath\\ConsoleApp1.exe";
                var proc = System.Diagnostics.Process.Start(filename, text);
                proc.CloseMainWindow();
                proc.Close();

At least this is what I found out, maybe Spotaware team can provide you a better solution...

bye


@paolo.panicali

paolo.panicali
30 Jul 2022, 15:23 ( Updated at: 21 Dec 2023, 09:22 )

Quartz 3.4.0 targets to Net 4.6 You have to install Quartz 2.6.0 which is supported by NET 4.0, the one Ctrader Targets

Hello, use Quartz Version 2.6.2. I installed 3.4 and got the same error...Quartz targets to net 4.6....installing 2.6 you can compile on Ctrader, just did it.

as you can see quartz last version targets to net 4.6

quartz 2.6.2 is compatible with a project targeting net 4.0 as Ctrader projects are.

bye.

 


@paolo.panicali

paolo.panicali
28 Jul 2022, 17:05

Telegram notifications whenever a Trade is Opened or Closed and an update of opened positions every hour

Hello I coded this so that I know when my bot running on a VPS opens or closes a position and I get an update every hour. Do not try to send a message every second, 1) because telegram does not allow 2) keep calm.

You have to grant AccessRights.Internet otherwise the bot won't be able to send messages(just copy paste the code and when prompted you have to click Yes); also, set the timeframe to 5 minutes if you want the updates, otherwise you can set it to 1h timeframe and you will only get the position Opened and Closed message.

Of course you first have to create a Telegram bot and make him joining a group as previously explained from others.

 

// Telegram notifications on Open, Close position and Update every hour
// by paolo panicali july 2022

using System;
using System.Linq;
using cAlgo.API;

using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.IO;
using System.Net;
using System.Text;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.Internet)]
    public class July19TelegramOpenCloseUpdate : Robot
    {
        string text, urlString, apiToken, chatId;

        protected override void OnStart()
        {
            Positions.Opened += PositionsOnOpened;
            Positions.Closed += PositionsOnClosed;
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            apiToken = "your bot token";
            chatId = "chat id";
        }

        protected override void OnBar()
        {
            if (Bars.OpenTimes.LastValue.Minute == 5)
            {
                SendMessageToTelegram();
            }
        }


        protected void SendMessageToTelegram()
        {
            foreach (var position in Positions)
            {
                text = "UPDATE CURRENTLY OPEN POSITION : ////--- BOTNAME: " + position.Label + "--- Symbol: " + position.SymbolName + "---- ENTRY: " + position.EntryPrice + "---- SL: " + position.StopLoss + "---- TP: " + position.TakeProfit + "---- TIME UTC: " + position.EntryTime + "---- PROFIT:  " + position.Pips + " pips";
                urlString = "https://api.telegram.org/bot{0}/sendMessage?chat_id={1}&text={2}";
                urlString = String.Format(urlString, apiToken, chatId, text);
                WebRequest request = WebRequest.Create(urlString);
                Stream rs = request.GetResponse().GetResponseStream();
                System.Threading.Thread.Sleep(5000);
            }
        }

        private void PositionsOnOpened(PositionOpenedEventArgs args)
        {
            Print("Position opened {0}", args.Position.SymbolName);

            text = "NEW TRADE OPENED : ////--- BOTNAME: " + args.Position.Label + "--- Symbol: " + args.Position.SymbolName + "---- ENTRY: " + args.Position.EntryPrice + "---- SL: " + args.Position.StopLoss + "---- TP: " + args.Position.TakeProfit + "---- TIME UTC: " + args.Position.EntryTime + "---- PROFIT:  " + args.Position.Pips + " pips";
            urlString = "https://api.telegram.org/bot{0}/sendMessage?chat_id={1}&text={2}";
            urlString = String.Format(urlString, apiToken, chatId, text);
            WebRequest request = WebRequest.Create(urlString);
            Stream rs = request.GetResponse().GetResponseStream();
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;
            Print("Position closed with {0} profit", position.SymbolName);

            text = "TRADE CLOSED : ////--- BOTNAME: " + args.Position.Label + "--- Symbol: " + args.Position.SymbolName + "---- ENTRY: " + args.Position.EntryPrice + "---- SL: " + args.Position.StopLoss + "---- TP: " + args.Position.TakeProfit + "---- TIME UTC: " + args.Position.EntryTime + "---- PROFIT:  " + args.Position.Pips + " pips";
            urlString = "https://api.telegram.org/bot{0}/sendMessage?chat_id={1}&text={2}";
            urlString = String.Format(urlString, apiToken, chatId, text);
            WebRequest request = WebRequest.Create(urlString);
            Stream rs = request.GetResponse().GetResponseStream();

        }
    }
}
 

Hope this will help, bye.


@paolo.panicali