Topics
Replies
algobeginner
12 Jan 2025, 23:23
( Updated at: 12 Jan 2025, 23:43 )
Update - lot cleaner , need work bodylenght ( 9 )
import Foundation
import Combine
class FIXClientViewModel: ObservableObject {
@Published var connectionStatus: String = "Disconnected"
@Published var receivedMessage: String = ""
private var client: FIXClient?
private var config: Config?
init() {
loadConfig()
}
func loadConfig() {
guard let configURL = Bundle.main.url(forResource: "config", withExtension: "json") else {
print("Config file not found.")
return
}
do {
let data = try Data(contentsOf: configURL)
let config = try JSONDecoder().decode(Config.self, from: data)
self.config = config
setupClient()
} catch {
print("Error loading config: \(error)")
}
}
func setupClient() {
guard let config = config else {
return
}
client = FIXClient(host: config.Host, port: config.Port, ssl: config.SSL)
client?.setConnectedCallback { [weak self] in
self?.connectionStatus = "Connected"
}
client?.setDisconnectedCallback { [weak self] error in
self?.connectionStatus = error != nil ? "Disconnected" : "Error"
}
client?.setMessageReceivedCallback { [weak self] message in
self?.receivedMessage = message.getMessage()
}
}
func connectToServer() {
client?.startService()
}
struct MessageField {
let tag: Int
let value: String
}
func sendLogonMessage() {
guard let config = config else {
return
}
let timestamp = getCurrentUTCTimestamp()
// Define the fields in the correct order for the Logon message (35=A)
let messageFields: [MessageField] = [
MessageField(tag: 8, value: config.BeginString), // 8=FIX.4.4 (BeginString)
MessageField(tag: 9, value: ""), // 9=BodyLength (will be calculated)
MessageField(tag: 35, value: "A"), // 35=A (Logon message type)
MessageField(tag: 49, value: config.SenderCompID), // 49=SenderCompID (ID of the trading party)
MessageField(tag: 56, value: config.TargetCompID), // 56=CSERVER (ID of the target component)
MessageField(tag: 34, value: String(1)), // 34=1 (MsgSeqNum, sequence number)
MessageField(tag: 52, value: timestamp), // 52=SendingTime (will be set dynamically)
MessageField(tag: 57, value: "QUOTE"), // 57=TRADE (TargetSubID)
MessageField(tag: 50, value: "Quote"), // 50=Quote (SenderSubID)
MessageField(tag: 98, value: "0"), // 98=0 (EncryptMethod, no encryption)
MessageField(tag: 108, value: config.HeartBeat), // 108=30 (Heartbeat interval)
MessageField(tag: 141, value: "Y"), // 141=Y (ResetSeqNumFlag)
MessageField(tag: 553, value: config.Username), // 553=Username (user ID)
MessageField(tag: 554, value: config.Password), // 554=Password (user password)
MessageField(tag: 10, value: "") // 10=Checksum (calculated later)
]
// Create the FIX message object
var logonMessage = FIXMessage()
// Add fields to the FIX message in the defined order, excluding 9 and 10 for now
for field in messageFields {
logonMessage.setField(field.tag, field.value)
}
// Dynamically set the SendingTime (52) to the current UTC timestamp
let currentTime = getCurrentUTCTimestamp()
logonMessage.setField(52, currentTime) // Set SendingTime (52)
// Now, calculate the message body length (excluding the BodyLength itself, i.e., excluding tag 9)
let messageString = logonMessage.getMessage()
// Calculate the message length (excluding the BodyLength field itself)
let messageLength = messageString.count + 1 // Include the Message Length field itself (9)
let messageLengthString = String(messageLength)
// Now, set the '9' field (BodyLength) in the second position
logonMessage.setField(9, messageLengthString) // Add BodyLength as second field
// Calculate checksum (tag 10)
let checksum = calculateChecksum(for: messageString)
// Set the '10' field with the calculated checksum as the last field
logonMessage.setField(10, checksum) // Add checksum at the end of the message
// Generate the fixed-format message string
let fixedFormatMessage = logonMessage.getMessage()
// Debugging: print the logon message in fixed format
print("Logon Message (Fixed Format): \(fixedFormatMessage)")
// Send the logon message
client?.send(logonMessage)
}
}
// Function to get the current UTC timestamp in the required format (yyyyMMdd-HH:mm:ss)
func getCurrentUTCTimestamp() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd-HH:mm:ss"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC") // Set the timezone to UTC
let date = Date()
return dateFormatter.string(from: date)
}
// Example checksum calculation function (you will need to implement this based on your specific needs)
func calculateChecksum(for message: String) -> String {
let checksum = message.reduce(0) { $0 + Int($1.asciiValue ?? 0) }
return String(checksum % 256)
}
@algobeginner
algobeginner
11 Jan 2025, 21:22
Swift code in IDE
import Cocoa
import Foundation
import Network
// Configuration for FIX API
struct FIXConfig {
var Host: String
var Port: Int
var SSL: Bool
var Username: String
var Password: String
var BeginString: String
var SenderCompID: String
var SenderSubID: String
var TargetCompID: String
var TargetSubID: String
var HeartBeat: Int
}
// Get current timestamp in FIX-compatible format
func getCurrentTimestamp() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd-HH:mm:ss"
return dateFormatter.string(from: Date())
}
// Calculate the checksum for the message (FIX requires it for integrity)
func generateChecksum(for message: String) -> String {
let messageBytes = [UInt8](message.utf8)
let checksum = messageBytes.reduce(0, { $0 + Int($1) }) % 256
return String(format: "%03d", checksum)
}
// Function to handle connection and sending logon message
func connectToServer(config: FIXConfig) -> NWConnection {
let host = NWEndpoint.Host(config.Host)
let port = NWEndpoint.Port(integerLiteral: UInt16(config.Port))
let connection = NWConnection(host: host, port: port, using: .tcp)
connection.stateUpdateHandler = { state in
switch state {
case .ready:
print("Connection established. Sending Logon message...")
sendLogonMessage(connection: connection, config: config)
case .failed(let error):
print("Connection failed with error: \(error)")
default:
break
}
}
connection.start(queue: .global())
return connection
}
// Function to send Logon Message
func sendLogonMessage(connection: NWConnection, config: FIXConfig) {
var logonMessage = """
8=\(config.BeginString)\u{1}35=A\u{1}49=\(config.SenderCompID)\u{1}56=\(config.TargetCompID)\u{1}34=1\u{1}52=\(getCurrentTimestamp())\u{1}108=\(config.HeartBeat)\u{1}
"""
let checksum = generateChecksum(for: logonMessage)
logonMessage.append("10=\(checksum)\u{1}")
print("Sending logon message: \(logonMessage)") // Log the message
let data = Data(logonMessage.utf8)
connection.send(content: data, completion: .contentProcessed({ error in
if let error = error {
print("Error sending logon message: \(error)")
} else {
print("Logon message sent successfully.")
requestMarketData(connection: connection, config: config)
}
}))
// Start listening for messages after sending logon
listenForMessages(connection: connection)
}
// Function to send Market Data Request for EUR/USD
func requestMarketData(connection: NWConnection, config: FIXConfig) {
let mdReqID = "EURUSD_MarketData"
let subscriptionRequestType = "1" // Snapshot + Updates
let marketDepth = "1" // Top of book
let noMDEntryTypes = "1" // Number of MD Entry Types
let mdEntryType = "0" // Bid
let noRelatedSym = "1" // Number of related symbols
let symbol = "1" // EUR/USD symbol
let mdUpdateType = "0" // Full refresh
var marketDataRequest = """
8=\(config.BeginString)\u{1}35=V\u{1}49=\(config.SenderCompID)\u{1}56=\(config.TargetCompID)\u{1}34=2\u{1}52=\(getCurrentTimestamp())\u{1}262=\(mdReqID)\u{1}
263=\(subscriptionRequestType)\u{1}264=\(marketDepth)\u{1}265=\(noMDEntryTypes)\u{1}269=\(mdEntryType)\u{1}146=\(noRelatedSym)\u{1}55=\(symbol)\u{1}
265=\(mdUpdateType)\u{1}
"""
let checksum = generateChecksum(for: marketDataRequest)
marketDataRequest.append("10=\(checksum)\u{1}")
print("Sending market data request: \(marketDataRequest)") // Log the message
let data = Data(marketDataRequest.utf8)
connection.send(content: data, completion: .contentProcessed({ error in
if let error = error {
print("Error sending market data request: \(error)")
} else {
print("Market data request sent successfully.")
}
}))
}
// Listen for incoming messages and handle logon acknowledgment or market data responses
func listenForMessages(connection: NWConnection) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 1024) { (data, context, isComplete, error) in
if let data = data {
let receivedMessage = String(decoding: data, as: UTF8.self)
print("Raw received message: \(receivedMessage)") // Log the raw message
// Print raw bytes
print("Raw bytes: \(data.map { String(format: "%02x", $0) }.joined(separator: " "))")
// Debug: Check if we're receiving an empty message
if data.isEmpty {
print("Received an empty message. Waiting for more data...")
}
// Handle the different message types (A = Logon, V = Market Data)
let messageType = receivedMessage.split(separator: "\u{1}").first { $0.hasPrefix("35=") }?.split(separator: "=").last ?? ""
if messageType == "A" {
// Logon acknowledgment received
print("Logon acknowledgment received!")
// Now, you can send the market data request here if you haven't yet
} else if messageType == "V" {
// Market Data response (Type V)
print("Received Market Data Update")
processMarketDataUpdate(receivedMessage)
} else {
print("Received unhandled message: \(receivedMessage)")
}
}
// Handle when the connection is complete or encounters an error
if isComplete {
connection.cancel()
print("Connection closed.")
} else if let error = error {
print("Error receiving message: \(error)")
connection.cancel()
} else {
// Continue listening for more messages
listenForMessages(connection: connection)
}
}
}
// Example: Process Market Data Update
func processMarketDataUpdate(_ message: String) {
// Print and process the market data response
print("Processing Market Data Update: \(message)")
// Example: You can extract the bid/ask data from the message.
// You will need to adjust parsing according to your FIX message format.
let messageParts = message.split(separator: "\u{1}") // Split by the ASCII delimiter
for part in messageParts {
print("Part: \(part)") // Print each part of the response message
}
}
// macOS ViewController
class ViewController: NSViewController {
let fixSessionManager = FIXSessionManager()
override func viewDidLoad() {
super.viewDidLoad()
// Start FIX session after the view is loaded
fixSessionManager.startFIXSession()
}
}
config
class FIXSessionManager {
func startFIXSession() {
let config = FIXConfig(
Host: "demo-uk-eqx-02.p.ctrader.com",
Port: 5201,
SSL: false,
Username: "1111111",
Password: "password",
BeginString: "FIX.4.4",
SenderCompID: "demo.ctrader.1111111",
SenderSubID: "QUOTE",
TargetCompID: "cServer",
TargetSubID: "QUOTE",
HeartBeat: 30
)
let connection = connectToServer(config: config)
listenForMessages(connection: connection)
}
}
still no response from server , any idea how to get this working , I tried this PythonKit but its so buggy it won't load even after environment creation for Python and Hardened Runtime disabled Library Validation .
Yes I tried, googling , AI , but no solution .
@algobeginner
algobeginner
09 Jan 2025, 07:48
( Updated at: 10 Jan 2025, 06:10 )
RE: Copy button for Values
thank you , I tried only AI 😁but I see good old google is better for answering some questions .
firemyst said:
Have you tried searching Google for answers on how to do it in C#?
@algobeginner
algobeginner
06 Jan 2025, 00:09
RE: Price predictions in calgo bot ?
PanagiotisCharalampous said:
Hi there,
This example uses the built in Linear Regression Forecast which is based on a formula.
Best regards,
Panagiotis
So to use of learned Linear Regression model for forecast should be in separate app through API market data feed , or is there some library which allows to import trained model to perform this inside calgo bot ?
@algobeginner
algobeginner
31 Dec 2024, 16:45
( Updated at: 02 Jan 2025, 07:06 )
RE: RE: RE: CSV Export and Load
PanagiotisCharalampous said:
algobeginner said:
PanagiotisCharalampous said:
Hi there,
Please share a screenshot of the exported data so that we can check.
Best regards,
Panagiotis
Hi there,
Did you try removing the header. I don't think it is necessary.
Best regards,
Panagiotis
Yes I did try and then it nothing happens . ( I mean the test doesn't start )
Also I have noticed if I try open External Process for CBot the Ctrader crash itself .
@algobeginner
algobeginner
31 Dec 2024, 10:56
( Updated at: 02 Jan 2025, 07:06 )
https://clickalgo.com/risk-reward-mac-free can be found here
@algobeginner
algobeginner
31 Dec 2024, 00:00
do you get any warnings about obsolete when you compile code on Mac ?
@algobeginner
algobeginner
30 Dec 2024, 10:31
( Updated at: 30 Dec 2024, 10:41 )
RE: Price predictions in calgo bot ?
PanagiotisCharalampous said:
Hi there,
Can you please explain which example you are referring to?
Best regards,
Panagiotis
it using indicator LinearRegressionForecast
_ which I'm wonder if is trained model as name would suggest from Machine Learning ,or just some formula do calculations based on median's of source ?
if this utilise trained model could we somehow import our own model from MLX into Bot to improve accuracy for specific pair ?
Ctrader heavy load CPU during optimisation but it have lot of spare computing power on GPU left so it could use it .
This example code : → using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None, AddIndicators = true)]
public class LinearRegressionForecastSample : Robot
{
private double _volumeInUnits;
private LinearRegressionForecast _linearRegressionForecast;
[Parameter("Volume (Lots)", DefaultValue = 0.01)]
public double VolumeInLots { get; set; }
[Parameter("Stop Loss (Pips)", DefaultValue = 10, MaxValue = 100, MinValue = 1, Step = 1)]
public double StopLossInPips { get; set; }
[Parameter("Take Profit (Pips)", DefaultValue = 10, MaxValue = 100, MinValue = 1, Step = 1)]
public double TakeProfitInPips { get; set; }
[Parameter("Label", DefaultValue = "LinearRegressionForecastSample")]
public string Label { get; set; }
[Parameter("Source", Group = "Linear Regression Forecast")]
public DataSeries Source { get; set; }
[Parameter("Periods", DefaultValue = 9, Group = "Linear Regression Forecast", MinValue = 0)]
public int Periods { get; set; }
public Position[] BotPositions
{
get
{
return Positions.FindAll(Label);
}
}
protected override void OnStart()
{
_volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
_linearRegressionForecast = Indicators.LinearRegressionForecast(Source, Periods);
}
protected override void OnBarClosed()
{
if (Bars.ClosePrices.Last(0) > _linearRegressionForecast.Result.Last(0) && Bars.ClosePrices.Last(1) <= _linearRegressionForecast.Result.Last(1))
{
ClosePositions(TradeType.Sell);
ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
}
else if (Bars.ClosePrices.Last(0) < _linearRegressionForecast.Result.Last(0) && Bars.ClosePrices.Last(1) >= _linearRegressionForecast.Result.Last(1))
{
ClosePositions(TradeType.Buy);
ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
}
}
private void ClosePositions(TradeType tradeType)
{
foreach (var position in BotPositions)
{
if (position.TradeType != tradeType) continue;
ClosePosition(position);
}
}
}
}
@algobeginner
algobeginner
28 Dec 2024, 20:12
RE: Optimisation Mac vs Windows
PanagiotisCharalampous said:
Hi there,
It seems you are using the genetic algorithm for optimization. In this case passes will be different even between subsequent optimization on the same machine.
Best regards,
Panagiotis
Yes it’s genetic , is grid more precise ?
@algobeginner
algobeginner
28 Dec 2024, 10:48
RE: Stop loss retry
firemyst said:
How do you know it's not an issue with your code that the SL and TP aren't being set?
Why don't you post a sample of the code that reproduces the issue so people can have a look?
{ protected override void OnStart()
{ Positions.Opened += Positions_Opened; } private void Positions_Opened(PositionOpenedEventArgs obj) {
if(obj.Position.StopLoss == null)
}
this seem to be answer a little bit obsolete, if this could be directly checked upon execution but that probably down the async 😌
@algobeginner
algobeginner
28 Dec 2024, 10:23
RE: Stop loss retry
firemyst said:
How do you know it's not an issue with your code that the SL and TP aren't being set?
Why don't you post a sample of the code that reproduces the issue so people can have a look?
Thanks for advice , but I doubt the code is issue as it occurs only on certain dates across different trading brokers .
came cross this on bar logics , basic three white soldiers , sma .
if it’s necessary I post codes but it’s stock version with optimised parameters .
the purpose of the question is if there is method to verify if during market order the stop loss can’t be set to prevent from open .
@algobeginner
algobeginner
27 Dec 2024, 14:30
RE: CSV Export and Load
PanagiotisCharalampous said:
Hi there,
Please share a screenshot of the exported data so that we can check.
Best regards,
Panagiotis
@algobeginner
algobeginner
25 Dec 2024, 18:35
I wonder if there is method to to run a optimisation for year or all available data , and get things like best fitness and parameters for each month or day as result instead of pass numbers ?
I see option save Optimisations but all this does is save all passes with numbers and 4 files .
@algobeginner
algobeginner
24 Dec 2024, 16:17
How about use your own historical data to emulate this factor ?
@algobeginner
algobeginner
24 Dec 2024, 11:19
RE: IDE for CTrader
PanagiotisCharalampous said:
Hi there,
The source code for cTrader is not available since cTrader is not an open source project.
Best regards,
Panagiotis
What IDE would you recommend for beginner to see all possible combinations of var and strings ?
especially I'm interested to discover Bars Reverses , to reduce computing time and identify breaks more often without use of indicators .
Would this works ?
Aggregation:
Average(): Computes the average of a sequence of numeric values.
Sum(): Computes the sum of a sequence of numeric values.
Max(): Returns the maximum value in a sequence.
Min(): Returns the minimum value in a sequence.
Filtering:
Where(): Filters a sequence of values based on a predicate.
Ordering:
OrderBy(): Sorts the elements of a sequence in ascending order.
OrderByDescending(): Sorts the elements of a sequence in descending order.
@algobeginner
algobeginner
24 Dec 2024, 11:19
RE: IDE for CTrader
PanagiotisCharalampous said:
Hi there,
The source code for cTrader is not available since cTrader is not an open source project.
Best regards,
Panagiotis
What IDE would you recommend for beginner to see all possible combinations of var and strings ?
especially I'm interested to discover Bars Reverses , to reduce computing time and identify breaks more often without use of indicators .
Would this works ?
Aggregation:
Average(): Computes the average of a sequence of numeric values.
Sum(): Computes the sum of a sequence of numeric values.
Max(): Returns the maximum value in a sequence.
Min(): Returns the minimum value in a sequence.
Filtering:
Where(): Filters a sequence of values based on a predicate.
Ordering:
OrderBy(): Sorts the elements of a sequence in ascending order.
OrderByDescending(): Sorts the elements of a sequence in descending order.
@algobeginner
algobeginner
14 Jan 2025, 09:29
Number of shares ordered. This
represents the number of shares
for equities or based on normal
convention the number of
contracts for options, futures,
convertible bonds, etc. Maximum
precision is 0.01 (Prior to FIX 4.2
this field was of type int) -
as far as I know all indices start from 0.10 and It’s also minimum value
@algobeginner