This page provides several Python and C# code examples for creating native plugins, including tools for manual or algorithmic trading in cTrader.
Plugin sample repositories
Comprehensive plugin code samples, including ready-to-run templates for various UI areas and functionalities, are available in separate Python and C# repositories in GitHub.
Tip
Use customisable parameters in both C# and Python plugins to achieve greater flexibility. Customisable parameters for C# plugins are declared in the regular C# code, while Python plugins require customisable parameters declared in their .cs files.
Display a website in a chart frame
The following plugin displays the cTrader Store website inside a separate chart frame.
Once per minute, the plugin below saves the total account profit and loss (P&L) into a file using the local storage feature and the current timestamp as the file name. It also displays the same information in a separate section in Active Symbol Panel (ASP).
importclrclr.AddReference("cAlgo.API")fromcAlgo.APIimport*classGrossPnL():defon_start(self):self.textBlock=TextBlock()self.textBlock.Text="Starting..."self.textBlock.FontSize=15self.textBlock.FontWeight=FontWeight.ExtraBoldself.textBlock.TextAlignment=TextAlignment.Centerself.textBlock.Padding=Thickness(5,5,5,5)aspBlock=api.Asp.SymbolTab.AddBlock("Gross P&L")aspBlock.Child=self.textBlockapi.Timer.Start(60)defon_timer(self):timestamp=api.Server.TimeInUtcresult=timestamp.ToString("HH mm ss")api.LocalStorage.SetString(result,f"{api.Account.UnrealizedGrossProfit}",LocalStorageScope.Device)self.textBlock.Text=f"{result}: {api.Account.UnrealizedGrossProfit}"
Display a separate window with a custom control
The plugin below adds a custom button to a detached window. On click, the control adds a take-profit level for all open positions but only if a position does not have a previously established take profit.
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingcAlgo.API;usingcAlgo.API.Collections;usingcAlgo.API.Indicators;usingcAlgo.API.Internals;namespacecAlgo.Plugins{[Plugin(AccessRights = AccessRights.None)]publicclassProtectionPlugin:Plugin{privateButton_buttonAddTakeProfit;privateWindow_window;protectedoverridevoidOnStart(){_buttonAddTakeProfit=newButton{BackgroundColor=Color.SeaGreen,Height=50,Text="Add Take Profit"};_buttonAddTakeProfit.Click+=AddTakeProfit;_window=newWindow{Height=150,Width=150,Padding=newThickness(5,10,10,5),};_window.Child=_buttonAddTakeProfit;_window.Show();}privatevoidAddTakeProfit(ButtonClickEventArgsargs){foreach(varpositioninPositions){if(position.TakeProfitisnull){position.ModifyTakeProfitPips(20);}}}}}
importclrclr.AddReference("cAlgo.API")fromcAlgo.APIimport*classProtectionPlugin():defon_start(self):self.buttonAddTakeProfit=Button()self.buttonAddTakeProfit.BackgroundColor=Color.SeaGreenself.buttonAddTakeProfit.Height=50self.buttonAddTakeProfit.Text="Add Take Profit"self.buttonAddTakeProfit.Click+=self.On_add_take_profit_clickself.window=Window()self.window.Height=150self.window.Width=150self.window.Padding=Thickness(5,10,10,5)self.window.Child=self.buttonAddTakeProfitself.window.Show()defOn_add_take_profit_click(self,args):forpositioninapi.Positions:ifposition.TakeProfitisNone:position.ModifyTakeProfitPips(20)
Display information about bar prices in Trade Watch display
When built, this plugin adds a new tab to Trade Watch panel. This tab contains a two-by-two grid that displays information about the last known bar prices for the m1 timeframe and the "USDJPY" symbol.
The following plugin detects which ChartFrame is currently active. Inside a custom block in the ASP, the plugin shows the percentage difference between the current price of the symbol for which this ChartFrame is opened and the price of this symbol approximately one month ago.
usingSystem;usingcAlgo.API;usingcAlgo.API.Collections;usingcAlgo.API.Indicators;usingcAlgo.API.Internals;namespacecAlgo.Plugins{[Plugin(AccessRights = AccessRights.None)]publicclassActiveFrameChangedSample:Plugin{// Declaring the necessary UI elementsprivateGrid_grid;privateTextBlock_percentageTextBlock;privateFrame_activeFrame;protectedoverridevoidOnStart(){// Initialising the grid and the TextBlock// displaying the percentage difference_grid=newGrid(1,1);_percentageTextBlock=newTextBlock{HorizontalAlignment=HorizontalAlignment.Center,VerticalAlignment=VerticalAlignment.Center,Text="Monthly change: ",};_grid.AddChild(_percentageTextBlock,0,0);// Initialising a new block inside the ASP// and adding the grid as a childvarblock=Asp.SymbolTab.AddBlock("Monthly Change Plugin");block.Child=_grid;// Attaching a custom handler to the// ActiveFrameChanged eventChartManager.ActiveFrameChanged+=ChartManager_ActiveFrameChanged;}privatevoidChartManager_ActiveFrameChanged(ActiveFrameChangedEventArgsobj){if(obj.NewFrameisChartFrame){// Casting the Frame into a ChartFramevarnewChartFrame=obj.NewFrameasChartFrame;// Attaining market data for the symbol for which// the currently active ChartFrame is openedvardailySeries=MarketData.GetBars(TimeFrame.Daily,newChartFrame.Symbol.Name);// Calculating the monthly change and displaying it// inside the TextBlockdoublemonthlyChange=(newChartFrame.Symbol.Bid-dailySeries.ClosePrices[dailySeries.ClosePrices.Count-30])/100;_percentageTextBlock.Text=$"Monthly change: {monthlyChange}";}}}}
importclrclr.AddReference("cAlgo.API")fromcAlgo.APIimport*classActiveFrameChangedSample():defon_start(self):# Initialising the grid and the TextBlock displaying the percentage differencegrid=Grid(1,1)self.percentageTextBlock=TextBlock()self.percentageTextBlock.HorizontalAlignment=HorizontalAlignment.Centerself.percentageTextBlock.VerticalAlignment=VerticalAlignment.Centerself.percentageTextBlock.Text="Monthly change: "grid.AddChild(self.percentageTextBlock,0,0)# Initialising a new block inside the ASP and adding the grid as a childblock=api.Asp.SymbolTab.AddBlock("Monthly Change Plugin")block.Child=grid# Attaching an event handler to the ActiveFrameChanged eventapi.ChartManager.ActiveFrameChanged+=self.on_chart_manager_active_frame_changeddefon_chart_manager_active_frame_changed(self,args):ifargs.NewFrameisNoneorisinstance(args.NewFrame.__implementation__,ChartFrame)==False:returnnewChartFrame=ChartFrame(args.NewFrame)# Attaining market data for the symbol for which the currently active ChartFrame is openeddailySeries=api.MarketData.GetBars(TimeFrame.Daily,newChartFrame.Symbol.Name)# Calculating the monthly change and displaying it inside the TextBlockmonthlyChange=(newChartFrame.Symbol.Bid-dailySeries.ClosePrices[dailySeries.ClosePrices.Count-30])/100self.percentageTextBlock.Text=f"Monthly change: {monthlyChange}"