Initial commit

This commit is contained in:
Michael Schimmel
2026-01-28 09:10:52 +01:00
commit a1d2e96f8a
513 changed files with 19503 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Webhook", "Webhook\Webhook.csproj", "{4b67b9be-4382-4e2b-ad2d-372da3d81a9a}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4b67b9be-4382-4e2b-ad2d-372da3d81a9a}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4b67b9be-4382-4e2b-ad2d-372da3d81a9a}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4b67b9be-4382-4e2b-ad2d-372da3d81a9a}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4b67b9be-4382-4e2b-ad2d-372da3d81a9a}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+308
View File
@@ -0,0 +1,308 @@
/*
Webhook setup:
1. cmd as admin:
> netsh http add urlacl url=http://+:80/ctrader user=RAKI\Brummel
2. Windows Defender Firewall, Outgoing Rules:
New rule, Ports-->TCP-->local port = 80, remote ports = all
3. FritzBox:
New "MyFritz-Freigabe", HTTP-Server, Deviceport 80, external port 80, Folder "ctrader"
Result:
Webhook in Tradingview: http://raki.1k9zmiax0jpc2iys.myfritz.net:80/ctrader
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Resources;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Globalization;
using System.Text.Json;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo.Plugins;
[Plugin(AccessRights = AccessRights.FullAccess)]
public class Webhook : Plugin
{
private HttpListener listener;
private string lastMsg = "";
private bool msgProcessed = false;
private readonly CancellationTokenSource cancellationTokenSource = new();
private Task task;
private TradeInfo tradeInfo;
private Symbol symbol;
private readonly List<Chart> charts = new();
private class TradeInfo
{
public string Symbol { get; set; }
public double StopLoss { get; set; }
public int Risk { get; set; }
public double Buy { get; set; }
public double Sell { get; set; }
public double Open { get; set; }
public double Low { get; set; }
public double High { get; set; }
public double Close { get; set; }
public DateTime ReceiveTime { get; set; }
public List<Chart> Charts { get; set; }
}
protected override void OnStart()
{
listener = new HttpListener();
//listener.Prefixes.Add("http://localhost:3000/");
listener.Prefixes.Add("http://+:80/ctrader/");
listener.Start();
var cancellationToken = cancellationTokenSource.Token;
task = Task.Run(() =>
{
while( !cancellationToken.IsCancellationRequested )
{
// Wait for a request to come in
var context = listener.GetContext();
var request = context.Request;
// Read the request body
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
string m = reader.ReadToEnd();
Monitor.Enter(this);
try
{
if( m != lastMsg )
{
lastMsg = m;
msgProcessed = false;
}
}
finally
{
Monitor.Exit(this);
}
}
// Send a response
var response = context.Response;
response.StatusCode = 200;
response.ContentType = "text/plain";
var buffer = Encoding.UTF8.GetBytes("OK - cTrader");
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
response.OutputStream.Close();
}
}, cancellationToken);
Timer.Start(TimeSpan.FromSeconds(1));
Positions.Opened += (a) => { UpdateStops(); };
}
protected override void OnTimer()
{
ProcessMsg();
}
protected override void OnStop()
{
Timer.Stop();
cancellationTokenSource.Cancel();
task.Wait();
listener.Stop();
}
protected bool UpdateTradeInfo()
{
string m = "";
Monitor.Enter(this);
try
{
if( !msgProcessed )
{
msgProcessed = true;
m = lastMsg;
}
}
finally
{
Monitor.Exit(this);
}
if( m== "" )
return false;
Print( "Received: {0}", m );
tradeInfo = JsonSerializer.Deserialize<TradeInfo>(m);
tradeInfo.ReceiveTime = DateTime.Now;
symbol = Symbols.GetSymbol(tradeInfo.Symbol);
if( symbol == null )
{
Print( "Error: unknown symbol {0}", tradeInfo.Symbol );
return false;
}
tradeInfo.StopLoss = Math.Round( tradeInfo.StopLoss, symbol.Digits );
tradeInfo.Buy = Math.Round( tradeInfo.Buy, symbol.Digits );
tradeInfo.Sell = Math.Round( tradeInfo.Sell, symbol.Digits );
charts.Clear();
foreach (var frame in ChartManager)
if (frame is ChartFrame chartFrame)
if( chartFrame.Chart.Symbol == symbol )
charts.Add( chartFrame.Chart );
foreach (var chart in charts )
chart.DrawStaticText("Message", tradeInfo.ReceiveTime.ToString("HH:mm:ss")+ ": "+m, VerticalAlignment.Top, HorizontalAlignment.Right, chart.ColorSettings.ForegroundColor);
return true;
}
protected void ProcessMsg()
{
if( UpdateTradeInfo() )
{
foreach (var chart in charts )
{
chart.DrawHorizontalLine( "SL", tradeInfo.StopLoss, Color.White );
if( tradeInfo.Buy > 0 )
chart.DrawIcon("Buy" + chart.Bars.Count, ChartIconType.UpArrow, chart.Bars.Count - 1, chart.Bars.ClosePrices[chart.Bars.Count - 1], Color.Green);
if( tradeInfo.Sell > 0 )
chart.DrawIcon("Sell" + chart.Bars.Count, ChartIconType.DownArrow, chart.Bars.Count - 1, chart.Bars.ClosePrices[chart.Bars.Count - 1], Color.Red);
}
ManageOrders();
UpdateStops();
}
}
private PendingOrder pendingOrder;
private double CalculateVolume(double StopLoss)
{
var maxAmountRisked = Account.Equity * ((double)tradeInfo.Risk / 100);
return symbol.NormalizeVolumeInUnits(maxAmountRisked / (StopLoss/symbol.PipSize * symbol.PipValue), RoundingMode.Down);
}
protected void ManageOrders()
{
return;
if( Positions.Count > 0 || tradeInfo.Symbol != "GER40" )
return;
if( tradeInfo.Buy > 0 )
{
double buyPrice = Math.Round( tradeInfo.Buy+symbol.Spread, symbol.Digits );
double stopLossPrice = Math.Round( tradeInfo.StopLoss-symbol.Spread, symbol.Digits );
if( pendingOrder != null )
if( pendingOrder.TradeType != TradeType.Buy || pendingOrder.TargetPrice != buyPrice )
{
pendingOrder.Cancel();
pendingOrder = null;
}
if( pendingOrder == null )
{
TradeResult tradeResult = PlaceStopOrder(
TradeType.Buy, tradeInfo.Symbol,
2, // CalculateVolume( buyPrice-stopLossPrice ),
buyPrice, "Managed long",
(buyPrice-stopLossPrice)/symbol.PipSize, null);
if( tradeResult.IsSuccessful )
pendingOrder = tradeResult.PendingOrder;
}
}
else if( tradeInfo.Sell > 0 )
{
double sellPrice = Math.Round( tradeInfo.Sell-symbol.Spread, symbol.Digits );
double stopLossPrice = Math.Round( tradeInfo.StopLoss+symbol.Spread, symbol.Digits );
if( pendingOrder != null )
if( pendingOrder.TradeType != TradeType.Sell || pendingOrder.TargetPrice != sellPrice )
{
pendingOrder.Cancel();
pendingOrder = null;
}
if( pendingOrder == null )
{
TradeResult tradeResult = PlaceStopOrder(
TradeType.Sell, tradeInfo.Symbol,
2, // CalculateVolume( stopLossPrice-sellPrice ),
sellPrice, "Managed short",
(stopLossPrice-sellPrice)/symbol.PipSize, null);
if( tradeResult.IsSuccessful )
pendingOrder = tradeResult.PendingOrder;
}
}
}
protected void UpdateStops()
{
foreach (var position in Positions)
{
if (position.Symbol != symbol)
continue;
if( position.TradeType == TradeType.Buy )
{
double sl = Math.Round( tradeInfo.StopLoss-symbol.Spread, symbol.Digits );
if( !position.StopLoss.HasValue || position.StopLoss < sl )
ModifyPosition(position, sl, position.TakeProfit);
/*
if( tradeInfo.Close < sl )
{
position.Close();
continue;
}
double be = Math.Round( position.EntryPrice+symbol.Spread, symbol.Digits );
double sl_be = Math.Min( sl, be );
if( !position.StopLoss.HasValue || position.StopLoss < sl_be )
ModifyPosition(position, sl_be, position.TakeProfit);
*/
}
else
{
double sl = Math.Round( tradeInfo.StopLoss+symbol.Spread, symbol.Digits );
if( !position.StopLoss.HasValue || position.StopLoss > sl )
ModifyPosition(position, sl, position.TakeProfit);
/*
if( tradeInfo.Close > sl )
{
position.Close();
continue;
}
double be = Math.Round( position.EntryPrice-symbol.Spread, symbol.Digits );
double sl_be = Math.Max( sl, be );
if( !position.StopLoss.HasValue || position.StopLoss > sl_be )
ModifyPosition(position, sl_be, position.TakeProfit);
*/
}
}
}
}
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="cTrader.Automate" Version="*" />
</ItemGroup>
</Project>