Description
As a big fan of both cTrader and TradingView, I developed a plugin to embed TradingView charts directly inside cTrader. It allows me to analyze graphs in TradingView but trade in cTrader.
Advantages:
- Add as many TradingView charts as you want.
- Place a TradingView chart next to a cTrader chart to compare.
Disadvantages:
- TradingView charts are not persisted, so all chart data is lost when you close cTrader.
- TradingView prices may differ from your broker's prices, so double-check the actual price in cTrader before trading.
How to use the plugin:
- Download the plugin
- Double click on the downloaded file to install it
- Find new “TV” icon in the top menu
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using cAlgo.API;
namespace cAlgo.Plugins
{
#if DEBUG
[Plugin(AccessRights = AccessRights.FullAccess)]
#else
[Plugin(AccessRights = AccessRights.None)]
#endif
public class TradingView : Plugin
{
private const string SvgIcon = @"<svg width='32' height='32' xmlns='http://www.w3.org/2000/svg'>
<g>
<title>Layer 1</title>
<text font-weight='bold' xml:space='preserve' text-anchor='start' font-family='Noto Sans JP' font-size='24' id='svg_1' y='24.22783' x='-0.83541' stroke-width='0' stroke='#BFBFBF' fill='#BFBFBF'>TV</text>
</g>
</svg>";
private const string Html = @"
<style>
.trade-button {
color:white;
border:0;
border-radius:3px;
font-size:1.2rem;
padding-left: 10px;
padding-right: 10px;
}
.sell-button {
background-color: #A83D19;
margin-right:5px;
}
.sell-button:hover {
background-color: #EF5824;
}
.sell-button:active {
background-color: #A83D19;
}
.buy-button {
background-color: #006730;
margin-left:5px;
}
.buy-button:hover {
background-color: #10A651;
}
.buy-button:active {
background-color: #006730;
}
.back-button {
color:white;
border:0;
border-radius:3px;
font-size:1.2rem;
padding-left: 10px;
padding-right: 10px;
background-color: #131722;
height: 35;
}
.back-button:hover {
background-color: #2A2E39;
}
.back-button:active {
background-color: #131722;
}
.trade-buttons {
position: fixed;
top:0;
right:0;
margin-top:6px;
margin-right:10px;
display: {TRADE_BUTTONS_DISPLAY}
}
</style>
<script>
const symbolName = '{SYMBOL_NAME}';
const frameId = '{FRAME_ID}';
const timeFrame = '{TIMEFRAME}';
const timezone = '{TIMEZONE}';
const locale = '{LANGUAGE}';
const style = '{STYLE}';
</script>
<body style='overflow: hidden;margin:0px;'>
<!-- TradingView Widget BEGIN -->
<div class='tradingview-widget-container'>
<div id='tradingview_bcda9'></div>
<div class='tradingview-widget-copyright'><a href='https://www.tradingview.com/' rel='noopener nofollow' target='_blank'><span class='blue-text'>Track all markets on TradingView</span></a></div>
<script type='text/javascript' src='https://s3.tradingview.com/tv.js'></script>
<script type='text/javascript'>
new TradingView.widget(
{
'autosize': true,
'symbol': symbolName,
'interval': timeFrame,
'timezone': timezone,
'theme': 'dark',
'style': style,
'locale': locale,
'enable_publishing': false,
'allow_symbol_change': true,
'container_id': 'tradingview_bcda9',
'hide_side_toolbar': false,
'save_image': false
}
);
</script>
</div>
</body>
<!-- TradingView Widget END -->
";
private readonly Dictionary<string, int> _barTypes = new()
{
{"Bars", 0},
{"Candles", 1},
{"Hollow Candles", 9},
{"Heiken Ashi", 8},
{"Line", 2},
{"Area", 3},
{"Renko", 4},
{"Line Break", 7},
{"Kagi", 5},
{"Point and Figure", 6},
};
private readonly List<string> _ianaTimeZoneIds = new()
{
"Etc/GMT+12", "Etc/GMT+11", "America/Adak", "Pacific/Honolulu", "Pacific/Marquesas", "America/Anchorage",
"Etc/GMT+9", "America/Tijuana", "Etc/GMT+8", "America/Los_Angeles", "America/Phoenix", "America/Chihuahua",
"America/Denver", "America/Whitehorse", "America/Guatemala", "America/Chicago", "Pacific/Easter",
"America/Mexico_City", "America/Regina", "America/Bogota", "America/Cancun", "America/New_York",
"America/Port-au-Prince", "America/Havana", "America/Indianapolis", "America/Grand_Turk",
"America/Asuncion", "America/Halifax", "America/Caracas", "America/Cuiaba", "America/La_Paz",
"America/Santiago", "America/St_Johns", "America/Araguaina", "America/Sao_Paulo", "America/Cayenne",
"America/Buenos_Aires", "America/Montevideo", "America/Punta_Arenas", "America/Miquelon", "America/Bahia",
"Etc/GMT+2", "America/Godthab", "Atlantic/Azores", "Atlantic/Cape_Verde", "Etc/UTC", "Europe/London",
"Atlantic/Reykjavik", "Africa/Sao_Tome", "Africa/Casablanca", "Europe/Berlin", "Europe/Budapest",
"Europe/Paris", "Europe/Warsaw", "Africa/Lagos", "Europe/Bucharest", "Asia/Beirut", "Africa/Cairo",
"Europe/Chisinau", "Asia/Hebron", "Africa/Johannesburg", "Europe/Kiev", "Asia/Jerusalem", "Africa/Juba",
"Europe/Kaliningrad", "Africa/Khartoum", "Africa/Tripoli", "Africa/Windhoek", "Asia/Amman", "Asia/Baghdad",
"Asia/Damascus", "Europe/Istanbul", "Asia/Riyadh", "Europe/Minsk", "Europe/Moscow", "Africa/Nairobi",
"Europe/Volgograd", "Asia/Tehran", "Asia/Dubai", "Europe/Astrakhan", "Asia/Baku", "Europe/Samara",
"Indian/Mauritius", "Europe/Saratov", "Asia/Tbilisi", "Asia/Yerevan", "Asia/Kabul", "Asia/Tashkent",
"Asia/Qyzylorda", "Asia/Yekaterinburg", "Asia/Karachi", "Asia/Calcutta", "Asia/Colombo", "Asia/Katmandu",
"Asia/Almaty", "Asia/Dhaka", "Asia/Omsk", "Asia/Rangoon", "Asia/Bangkok", "Asia/Barnaul", "Asia/Hovd",
"Asia/Krasnoyarsk", "Asia/Novosibirsk", "Asia/Tomsk", "Asia/Shanghai", "Asia/Irkutsk", "Asia/Singapore",
"Australia/Perth", "Asia/Taipei", "Asia/Ulaanbaatar", "Australia/Eucla", "Asia/Chita", "Asia/Tokyo",
"Asia/Pyongyang", "Asia/Seoul", "Asia/Yakutsk", "Australia/Adelaide", "Australia/Darwin",
"Australia/Brisbane", "Australia/Sydney", "Pacific/Port_Moresby", "Australia/Hobart", "Asia/Vladivostok",
"Australia/Lord_Howe", "Pacific/Bougainville", "Asia/Srednekolymsk", "Asia/Magadan", "Pacific/Norfolk",
"Asia/Sakhalin", "Pacific/Guadalcanal", "Asia/Kamchatka", "Pacific/Auckland", "Etc/GMT-12", "Pacific/Fiji",
"Pacific/Chatham", "Etc/GMT-13", "Pacific/Tongatapu", "Pacific/Apia", "Pacific/Kiritimati"
};
private readonly Dictionary<string, string> _languages = new();
private WidgetSettings _settings;
protected override void OnStart()
{
foreach (var cultureInfo in CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.OrderBy(c => c.DisplayName))
_languages.TryAdd(cultureInfo.DisplayName, cultureInfo.IetfLanguageTag);
var icon = new SvgIcon(SvgIcon);
_ = Commands.Add(CommandType.ChartContainerToolbar, CommandCallback, icon);
_settings = LocalStorage.GetObject<WidgetSettings>("settings") ?? new WidgetSettings
{
Locale = "English",
Interval = "60",
Style = "Candles",
Symbol = "EURUSD",
Timezone = "Etc/UTC",
Title = "TradingView"
};
}
private CommandResult CommandCallback(CommandArgs args)
{
var rootPanel = new StackPanel();
rootPanel.Margin = new Thickness(10);
rootPanel.Width = 250;
rootPanel.Height = 210;
var title = new TextBox {Text = "Trading View"};
title.Text = _settings.Title;
title.TextChanged += _ => UpdateTitleSetting(title.Text);
rootPanel.AddChild(WrapWithTitle(title, "Title").SetMargin(0, 0, 0, 10));
var symbolName = new TextBox {Text = "EURUSD"};
symbolName.Text = _settings.Symbol;
symbolName.TextChanged += _ => UpdateSymbolSetting(symbolName.Text);
rootPanel.AddChild(WrapWithTitle(symbolName, "Symbol").SetMargin(0, 0, 0, 10));
var comboBoxStyle = new Style();
comboBoxStyle.Set(ControlProperty.Height, 18);
comboBoxStyle.Set(ControlProperty.HorizontalContentAlignment, HorizontalAlignment.Left);
var grid = new Grid();
rootPanel.AddChild(grid);
grid.AddColumn().SetWidthInStars(1);
grid.AddColumn().SetWidthInPixels(10);
grid.AddColumn().SetWidthInStars(1);
var intervalRow = grid.AddRow().Auto();
var interval = new ComboBox { Style = comboBoxStyle };
FillIntervals(interval);
interval.SelectedItem = TvTimeFrames.GetDisplayValue(_settings.Interval);
interval.SelectedItemChanged += _ => UpdateIntervalSetting(interval.SelectedItem);
grid.AddChild(WrapWithTitle(interval, "Interval"), intervalRow.Index, 0);
var timezone = new ComboBox { Style = comboBoxStyle };
foreach (var ianaId in _ianaTimeZoneIds)
timezone.AddItem(ianaId);
timezone.SelectedItem = _settings.Timezone;
timezone.SelectedItemChanged += _ =>
{
_settings.Timezone = timezone.SelectedItem;
SaveSettings();
};
grid.AddChild(WrapWithTitle(timezone, "Timezone"), intervalRow.Index, 2);
grid.AddRow().SetHeightInPixels(5);
var languageRow = grid.AddRow().Auto();
var languages = new ComboBox { Style = comboBoxStyle };
foreach (var language in _languages.Keys)
languages.AddItem(language);
languages.SelectedItem = _settings.Locale;
languages.SelectedItemChanged += _ =>
{
_settings.Locale = languages.SelectedItem;
SaveSettings();
};
grid.AddChild(WrapWithTitle(languages, "Language"), languageRow.Index, 0);
var barStyle = new ComboBox { Style = comboBoxStyle };
barStyle.SelectedItemChanged += _ =>
{
_settings.Style = barStyle.SelectedItem;
SaveSettings();
};
foreach (var barTypesValue in _barTypes.Keys)
barStyle.AddItem(barTypesValue);
barStyle.SelectedItem = _settings.Style;
grid.AddChild(WrapWithTitle(barStyle, "Bar's Style"), languageRow.Index, 2);
var openChartButtonStyle = new Style();
openChartButtonStyle.Set(ControlProperty.BackgroundColor, "#009345");
openChartButtonStyle.Set(ControlProperty.BackgroundColor, "#10A651", ControlState.Hover);
var openChartButton = new Button
{
Text = "Open Chart",
Margin = new Thickness(0, 20, 0, 0),
Style = openChartButtonStyle,
};
rootPanel.AddChild(openChartButton);
openChartButton.Click += _ => AddChart((ChartContainer) args.Context, _settings);
return new CommandResult(rootPanel);
}
private void UpdateIntervalSetting(string displayValue)
{
_settings.Interval = TvTimeFrames.GetValue(displayValue);
SaveSettings();
}
private void FillIntervals(ComboBox comboBox)
{
foreach (var displayValue in TvTimeFrames.GetAllDisplayValues()) comboBox.AddItem(displayValue);
}
private void UpdateSymbolSetting(string text)
{
_settings.Symbol = text;
SaveSettings();
}
private void UpdateTitleSetting(string title)
{
_settings.Title = title;
SaveSettings();
}
private void SaveSettings()
{
LocalStorage.SetObject("settings", _settings);
}
private ControlBase WrapWithTitle(ControlBase control, string title)
{
var stackPanel = new StackPanel();
stackPanel.AddChild(new TextBlock {Text = title, Margin = new Thickness(0, 0, 0, 3)});
stackPanel.AddChild(control);
return stackPanel;
}
private void AddChart(ChartContainer chartContainer, WidgetSettings settings)
{
var symbolName = settings.Symbol;
var customFrame = ChartManager.AddCustomFrame(settings.Title, chartContainer);
var webView = new WebView();
customFrame.Child = webView;
var html = Html
.Replace("{SYMBOL_NAME}", symbolName)
.Replace("{FRAME_ID}", customFrame.Id)
.Replace("{TIMEZONE}", settings.Timezone)
.Replace("{TIMEFRAME}", settings.Interval)
.Replace("{STYLE}", _barTypes[settings.Style].ToString())
.Replace("{LANGUAGE}", _languages[settings.Locale]);
#if DEBUG
File.WriteAllText(@"C:\Temp\tv.html", html);
#endif
webView.NavigateToStringAsync(html);
}
}
internal class TvTimeFrame
{
public TvTimeFrame(string displayValue, string tv)
{
DisplayValue = displayValue;
TV = tv;
}
public string DisplayValue { get; }
public string TV { get; }
}
internal static class TvTimeFrames
{
private static readonly TvTimeFrame[] _all =
{
new("1 minute", "1"),
new("2 minutes", "2"),
new("3 minutes", "3"),
new("5 minutes", "5"),
new("10 minutes", "10"),
new("15 minutes", "15"),
new("30 minutes", "30"),
new("45 minutes", "45"),
new("1 hour", "60"),
new("2 hours", "120"),
new("3 hours", "180"),
new("4 hours", "240"),
new("1 day", "D"),
new("1 week", "W"),
new("1 month", "M"),
new("3 months", "3M"),
new("6 months", "6M"),
new("12 months", "12M"),
new("1 range", "1R"),
new("10 ranges", "10R"),
new("100 ranges", "100R"),
new("1000 ranges", "1000R"),
};
public static IEnumerable<string> GetAllDisplayValues()
{
return _all.Select(i => i.DisplayValue);
}
public static string GetValue(string displayValue)
{
foreach (var tf in _all)
if (tf.DisplayValue == displayValue)
return tf.TV;
return "h1";
}
public static string GetDisplayValue(string value)
{
foreach (var tf in _all)
if (tf.TV == value)
return tf.DisplayValue;
return "1 hour";
}
}
internal record WidgetSettings
{
public string Title { get; set; }
public string Symbol { get; set; }
public string Interval { get; set; }
public string Timezone { get; set; }
public string Locale { get; set; }
public string Style { get; set; }
}
internal static class StaticExtensions
{
public static GridRow Auto(this GridRow row)
{
row.SetHeightToAuto();
return row;
}
public static ControlBase SetMargin(this ControlBase control, double left, double top, double right,
double bottom)
{
control.Margin = new Thickness(left, top, right, bottom);
return control;
}
}
}
Quant
Joined on 12.01.2014
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: TradingView.algo
- Rating: 5
- Installs: 109
Note that publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section, please use the Copyright Infringement Notification form to submit a claim.
Comments
Log in to add a comment.
really excellent addition and can see many other uses for this (such as pulling json feeds from the TV page etc).
nicely implemented