pick

Info
Username: | pick |
Name: | pick |
Member since: | 04 Oct 2022 |
About
Signature
Last Forum Posts
@Documentation example doesn't work: 30 May 2023, 11:22
coffeedarkmatter said:
Thanks Pick! That code works. And I now also understand how cTrader operates a bit better. I much appreciate your reply and the time taken. :)
How did you know the code did work, but needed threading to give a visual result earlier? I looked at the chart and indicator and didn't notice a spinning wheel or loading sign. And in the Task Manager the cTrader's CPU usage was very low. So I mistakenly assumed the code didn't do anything.
Sorry for the delayed response. I'm glad that you could reproduce a working sample! I initially just reduced the number of iterations in the loop to 5 and it populated. Then, I just removed the graphical side of it and began logging with the timings to find the culprit.
@DrawStaticText not displaying immediately: 25 May 2023, 16:24
couscousmckoy said:
Thanks Pick - I'll give that a try. Part of the problem was length of time it took to scroll through all historical bars to colour code certain bars. I've managed to irradicate this half of the issue by only updating bar colour on visible bars. Still leaves the 10seconds it takes to calculate which bars should be colour coded and unfortunately to work that out it has to work through a lot of bars from the start. I'll give threads a go though. Thank you for the help.
couscous
No worries - hopefully that can provide some benefit. Ten seconds just for the visible bars still sounds like a rather long time to compute. If you need any further help reducing this time, please could you elaborate more on what conditions you're colouring the bars with.
@DrawStaticText not displaying immediately: 25 May 2023, 13:50
What sort of tasks are you performing during this time consuming method? Can they be ran on another thread? Ideally I wouldn't want to block the main thread for so long. Below is an example of running the task on another thread:
protected override void Initialize()
{
Print("Starting long job");
Chart.DrawStaticText("LongJobWarning", "Warning: Long Job. Wait until this message disappears!!", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);
Task.Run(doLongJob);
}
async Task doLongJob()
{
await Task.Delay(10000); //10 second delay
BeginInvokeOnMainThread(() =>
{
Print("Finished Long Job");
Chart.RemoveObject("LongJobWarning");
});
}
@Documentation example doesn't work: 25 May 2023, 13:24
It works, but it takes a long time - mainly due to the Symbols.GetSymbol call (which must be done on the main thread) combined with how many symbols there are to load.
You can reduce the number of loops and it will populate faster, but if you want all symbols, below is a solution that I just quickly wrote up. It will populate the symbol names, then move on to filling in the descriptions.
Keep in mind that this is only a quick implementation and that it could probably be made more efficient:
protected override void Initialize()
{
ScrollViewer scrollViewer = new ScrollViewer
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
BackgroundColor = Color.Gold,
Opacity = 0.7,
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = ScrollBarVisibility.Visible,
Height = 300
};
Grid grid = new Grid(Symbols.Count + 1, 2)
{
BackgroundColor = Color.Gold,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
};
grid.AddChild(new TextBlock
{
Text = "Name",
Margin = 5,
ForegroundColor = Color.Black,
FontWeight = FontWeight.ExtraBold
}, 0, 0);
grid.AddChild(new TextBlock
{
Text = "Description",
Margin = 5,
ForegroundColor = Color.Black,
FontWeight = FontWeight.ExtraBold
}, 0, 1);
Chart.AddControl(scrollViewer);
scrollViewer.Content = grid;
List<string> strings = Symbols.ToList();
for (int i = 0; i < strings.Count; i++)
{
grid.AddChild(new TextBlock
{
Text = strings[i],
Margin = 5,
ForegroundColor = Color.Black,
FontWeight = FontWeight.ExtraBold
}, i + 1, 0);
}
foreach (string s in strings)
{
this.BeginInvokeOnMainThread(() =>
{
Symbol sym = Symbols.GetSymbol(s);
grid.AddChild(new Button
{
Text = sym.Description,
Margin = 5,
ForegroundColor = Color.Black,
FontWeight = FontWeight.ExtraBold
}, strings.IndexOf(s) + 1, 1);
});
}
}
@Is there a way to have bots use cTrader's current "user time" programmatically without parameters?: 24 May 2023, 11:54
I don't believe you can set the default for the indicator, but you can access the users current offset:
protected override void Initialize()
{
TimeSpan t = this.Application.UserTimeOffset;
Print("User time offset = " + t.TotalHours);
this.Application.UserTimeOffsetChanged += Application_UserTimeOffsetChanged;
}
private void Application_UserTimeOffsetChanged(UserTimeOffsetChangedEventArgs obj)
{
TimeSpan t = this.Application.UserTimeOffset;
Print("User time offset changed = " + t.TotalHours);
}
From there, it's easy to just combine the utc time with the offset for user time.
@Reduce infinity value: 18 May 2023, 19:26
o.o.d.exp said:
Great, I was able to successfully modify the indicator thanks to your help! Once it is perfected I will post the code so anyone who wants can download it.
I have one more question: the indicator draws horizontal opening session lines on the traditional candlestick chart, but when I change to heiken ashi candlesticks, the opening price lines disappear.
I assume this is because heiken ashi candles have a different calculation method to regular candles, so there is probably nothing to do about it.Do you think this is the problem, or is it possible to fix this?
You posted just after I went off yesterday - so I've just seen this. I've never worked with Heiken Ashi charts, but I'd assume it's due to the timeframe check:
if (openPrices)
if (TimeFrame <= TimeFrame.Hour) //Here
if (MarketSeries.OpenTime[index] >= londonOpen)
Chart.DrawTrendLine("_open london" + londonOpen, londonOpen, MarketSeries.Open[MarketSeries.OpenTime.GetIndexByTime(londonOpen)], londonClose, MarketSeries.Open[MarketSeries.OpenTime.GetIndexByTime(londonOpen)], Color.Blue);
If you change that to include Heikin timeframes, it may provide you a result:
if (TimeFrame <= TimeFrame.Hour || TimeFrame <= TimeFrame.HeikinHour)
Having not used Heikin Ashi charts before, but just having a light read about them, I'd assume this will produce a different value than if it were ran off of a standard timeframe. Give it a go and let me know how it goes!
@Reduce infinity value: 17 May 2023, 19:59
o.o.d.exp said:
Even though you didn't realise what I wanted, the indicator has improved a lot thanks to your advice!
I have now tried to add the code you told me, trying to be as precise as possible, but I get errors...
Sorry, I didn't realise what version of C# you were compiling. Change:
newestTime = Bars[^1].OpenTime;
to:
newestTime = Bars[Bars.Count - 1].OpenTime;
Also, it looks like you have an extra opening curly brace on line 52 in your screenshot - just delete that and the rest looks good.
@Reduce infinity value: 17 May 2023, 19:11
o.o.d.exp said:
Thanks, it's a real blessing to find helpful people like you!
I also made the last change you made, and it seems to work fine now. It has improved considerably, the first version was constantly causing cTrader to freeze every time I changed timeframe, and I always had to force close it and restart it.
I think the problem is due to the fact that the sessions drawn on the chart by the indicator are infinite! The person who created the indicator did not provide a parameter for setting a customised number of sessions. In fact, although it is much better now, it always seems a bit cumbersome for the platform to have to calculate infinite sessions backwards in time, when it could calculate three or four at most.
So going back to the title of my first post, what would it take to reduce that infinite value and be able to enter a custom value of sessions, so that everything runs smoother?
For example, I have a pivot point indicator that has a parameter to select the number of days back in time on which to calculate pivots (see image). Could I copy and paste that part of the code from the pivot indicator to the forex session indicator?
Apologies - I didn't realise that's what you wanted!
If you add a parameter:
[Parameter("MaxDays", DefaultValue = 5)]
public int maxDays { get; set; }
Add a global variable (it can be right below the line above, it just needs to be outside of a method - but inside the class):
DateTime newestTime; //Track newest time
Then, in the Initialize function, set a starting value:
protected override void Initialize()
{
openSeries = MarketData.GetSeries(TimeFrame.Hour);
newestTime = Bars[^1].OpenTime; //Set starting value
}
Then, at the top of the Calculate function, check if the bar calculating is too old:
public override void Calculate(int index)
{
DateTime time = Bars[index].OpenTime; //Get time of bar calculating
if (time > newestTime) //If it's newer than the newest time
newestTime = time; //Update newest time
if (time < newestTime.AddDays(-maxDays)) //Check if it's too old
return; //Return out of method
//Below is code that was already there...
//London Session
string today = Bars.OpenTimes[index].Day.ToString() + "/" + Bars.OpenTimes[index].Month.ToString() + "/" + Bars.OpenTimes[index].Year.ToString() + " ";
if (london)
{
.........
That should hopefully provide you with some filtering. Keep in mind that this count will include weekends, so it won't show 5 trading days.
@Reduce infinity value: 17 May 2023, 17:13
o.o.d.exp said:
Thank you, I succeeded. Now cTrader no longer gives me the error.
However, now it does not always draw the most recent sessions, as you can see in the picture.
And besides that it has a couple of other things to fix.
I don't think I'll be able to fix it completely even with your help, also because it doesn't seem fair to me to monopolize your time.Do you happen to do programming work in exchange for payment?
At least there's some progress on the error side. I just ran the indicator for the first time and that also appeared to be the case for me. Removing the normal check for the "londonPrice", "nyPrice" etc brought it back to drawing at current time (on my end, at least) without the error prompting.
Changing from:
if (double.IsNormal(londonMin) && double.IsNormal(londonMax) && double.IsNormal(londonPrice))
{
to:
if (double.IsNormal(londonMin) && double.IsNormal(londonMax))
At the moment, I don't offer any paid services, but if you require more help: there is a Telegram group for cTrader programming help in which I occasionally look at. Or of course, feel free to post here and if I see it, I'm more than happy to chime in if necessary!
@Reduce infinity value: 17 May 2023, 14:49
o.o.d.exp said:
Hi, thanks for your help.
This is my first attempt to modify a code without knowing anything about programming at all.
Comparing the original code with the one you sent me, it seems to me that the only difference is this additional string:if (double.IsNormal(londonMin) && double.IsNormal(londonMax) && double.IsNormal(londonPrice)) //Check all values are normal { //
So following your instructions I took the string in question and copied and pasted it to all the other sessions, replacing only the name of each session.
At the end I clicked on build but some errors came up.
This is the complete modified code:--
It looks like you have missed the final closing curly brace. Look in my previous response for the line that is simply just "} //" which comes after the "Chart.DrawStaticText" line. Other than that, it looks good.