Gamestudio Links
Zorro Links
Newest Posts
IBKR datasave problem
by NewbieZorro. 06/11/25 15:11
Marking Exit trades
by jcl. 06/11/25 14:02
SGT_FW
by Aku_Aku. 06/02/25 17:54
The Perfect Adventure Game
by tian. 05/27/25 04:32
ADX values
by Yogpot. 05/25/25 15:11
Transfer of Lots between Algos?
by Jack_Zodiac. 05/25/25 09:30
AUM Magazine
Latest Screens
Stug 3 Stormartillery
Iljuschin 2
Galactic Strike X
Zeal-X2
Who's Online Now
2 registered members (Quad, Ayumi), 451 guests, and 2 spiders.
Key: Admin, Global Mod, Mod
Newest Members
WardyJoubertIII, NewbieZorro, Squarei, tian, Yogpot
19139 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 5 of 9 1 2 3 4 5 6 7 8 9
DRL direct Feed from Zorro [Re: TipmyPip] #488431
11/09/24 17:07
11/09/24 17:07
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
It’s possible to pass the live data feed from Zorro Trader directly to a Deep Reinforcement Learning (DRL) model without having to call a function from Zorro each time. This can be achieved by running the DRL model in a separate Python script or process that continuously ingests the live data from Zorro in real-time, allowing it to learn and adapt independently. Here’s how to set this up:

Steps to Integrate Zorro’s Live Feed Directly into a DRL Model
Set Up a Data Stream from Zorro to Python:

Configure Zorro to save live market data into a continuously updated file or to use an inter-process communication (IPC) method, such as sockets or shared memory, to feed data into the Python DRL model.
Run the DRL Model as an Independent Python Process:

Implement the DRL model in a standalone Python script that continuously reads data from the Zorro feed and performs training in real-time.
The DRL model can process the data asynchronously and make trading decisions based on updated observations.
Implement Communication Back to Zorro for Trade Execution:

When the DRL model decides on a trade action, it can communicate this action back to Zorro, which will execute the trade.

Implementation Options
Option 1: Data Streaming Using File I/O
Zorro Script for Writing Data Feed:

Modify the Zorro run function to write the latest market data to a CSV file (e.g., live_data.csv) at each bar interval.

Code
function run()
{
    vars InputData = series(priceClose());  // Example data series
    
    // Save data to CSV file for the DRL model
    file_write("Data/live_data.csv", InputData, 0);

    // Execute trades based on external signals
    var signal = file_read("Data/drl_signal.txt");  // Read DRL action signal
    if (signal > 0.5)
        enterLong();
    else if (signal <= 0.5)
        enterShort();
}


Python DRL Script (Independent Process):

In a separate Python script, the DRL model continuously monitors live_data.csv for new data and updates its learning and action policy accordingly.

Code
import torch
import numpy as np
import time
from model import TradingModel  # Define your model in model.py

model = TradingModel(input_size=8, hidden_size=256)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = torch.nn.BCELoss()

def train_model(input_data, target):
    model.train()
    input_tensor = torch.tensor(input_data, dtype=torch.float32)
    target_tensor = torch.tensor([target], dtype=torch.float32)

    optimizer.zero_grad()
    prediction = model(input_tensor)
    loss = criterion(prediction, target_tensor)
    loss.backward()
    optimizer.step()
    return loss.item()

while True:
    # Read the latest data from live_data.csv
    try:
        data = np.loadtxt("Data/live_data.csv", delimiter=',')
        input_data = data[-1]  # Get the most recent row of data
        prediction = model(torch.tensor(input_data, dtype=torch.float32)).item()
        
        # Save the action decision back to a file that Zorro reads
        with open("Data/drl_signal.txt", "w") as f:
            f.write("1" if prediction > 0.5 else "0")  # Save the signal for Zorro
        
        # Optionally train model with feedback (e.g., profit from the last trade)
        # target = get_trade_feedback()  # You may define a function to get trade results
        # train_model(input_data, target)

    except Exception as e:
        print(f"Error reading data or training model: {e}")

    time.sleep(1)  # Polling interval, adjust based on data frequency


Option 2: Using Sockets for Real-Time Data Streaming
Set Up a Socket Server in the Python DRL Script:

Run a socket server in Python to continuously receive data from Zorro and send back trade actions.

Code
import socket
import torch
import numpy as np
from model import TradingModel

model = TradingModel(input_size=8, hidden_size=256)

# Initialize socket server
HOST = 'localhost'  
PORT = 65432        
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()

print("Waiting for Zorro connection...")

conn, addr = server.accept()
print(f"Connected by {addr}")

while True:
    data = conn.recv(1024)  # Adjust buffer size as needed
    if not data:
        break
    
    # Convert data to numpy array
    input_data = np.frombuffer(data, dtype=np.float32)
    
    # Make a prediction
    prediction = model(torch.tensor(input_data)).item()

    # Send decision to Zorro
    decision = b'1' if prediction > 0.5 else b'0'
    conn.sendall(decision)


Modify the Zorro Script to Send Data via Socket:

In the Zorro script, connect to the Python socket server to send live data and receive the model’s action signal.

Code
function run()
{
    vars InputData = series(priceClose());
    double Data[NumSignals];
    for(int i = 0; i < NumSignals; i++)
        Data[i] = InputData[i];

    // Send data to Python via socket
    int socket = socket_connect("localhost", 65432);
    if (socket != 0) {
        socket_send(socket, Data, sizeof(Data));  // Send data
        int action = socket_receive(socket);      // Receive action decision
        socket_close(socket);

        // Act on received decision
        if (action == '1')
            enterLong();
        else if (action == '0')
            enterShort();
    }
}


By running the DRL model as an independent process, it can continuously learn and adapt from real-time data while only sending trade decisions back to Zorro for execution. This setup provides the flexibility to train the DRL model in live environments without interrupting Zorro’s main trading operations.

In the Zorro platform, socket-based networking functions like socket_connect, socket_send, and socket_receive are not built-in, as Zorro’s lite-C scripting language does not natively support socket programming. However, you can achieve socket communication in Zorro using DLLs (Dynamic Link Libraries) to bridge between Zorro and Python for real-time data feeds.

Steps to Set Up Socket Communication Between Zorro and Python Using a DLL
Create a C/C++ Socket DLL:

Write a C/C++ library that implements socket functions (connect, send, receive, close).
Compile the library into a DLL that Zorro can load and call directly from the lite-C script.
Use the DLL in Zorro:

Load the DLL in your Zorro script.
Use the DLL functions to send data to and receive data from a Python socket server.
Example of a Simple C/C++ Socket DLL
Here’s a minimal example to create a C++ DLL for socket communication. This example provides functions for connecting, sending, receiving, and closing a socket.

C++ Socket DLL Code
Save this file as SocketDLL.cpp, and then compile it into a DLL.

Code
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

extern "C" {
    SOCKET sock = INVALID_SOCKET;

    __declspec(dllexport) int socket_connect(const char* ip, int port) {
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2,2), &wsaData);
        
        sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sock == INVALID_SOCKET) return -1;

        sockaddr_in clientService;
        clientService.sin_family = AF_INET;
        clientService.sin_addr.s_addr = inet_addr(ip);
        clientService.sin_port = htons(port);

        if (connect(sock, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
            closesocket(sock);
            WSACleanup();
            return -1;
        }
        return 0;
    }

    __declspec(dllexport) int socket_send(const char* data, int length) {
        if (sock == INVALID_SOCKET) return -1;
        return send(sock, data, length, 0);
    }

    __declspec(dllexport) int socket_receive(char* buffer, int length) {
        if (sock == INVALID_SOCKET) return -1;
        return recv(sock, buffer, length, 0);
    }

    __declspec(dllexport) void socket_close() {
        if (sock != INVALID_SOCKET) {
            closesocket(sock);
            WSACleanup();
        }
    }
}


Explanation:
socket_connect: Connects to the given IP and port.
socket_send: Sends data through the connected socket.
socket_receive: Receives data from the socket into a buffer.
socket_close: Closes the socket and cleans up resources.
Compile the DLL
Use a C++ compiler, like Microsoft Visual Studio, to compile this code into a DLL (e.g., SocketDLL.dll). Ensure it’s a 64-bit DLL if you’re using the 64-bit version of Zorro.

Zorro Script to Use the DLL
Place the compiled DLL (SocketDLL.dll) in the same directory as your Zorro script.
Use the DLL functions in your Zorro script to connect, send, and receive data.
Zorro lite-C Script Example

Code
function run()
{
    // Load the socket DLL
    int connect_result = call("SocketDLL.dll", "socket_connect", "localhost", 65432);

    if (connect_result == 0) {
        printf("\nConnected to socket.");

        // Example data to send
        double data[8] = { 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 };
        call("SocketDLL.dll", "socket_send", data, sizeof(data));

        // Buffer for receiving data
        char buffer[8];
        int bytes_received = call("SocketDLL.dll", "socket_receive", buffer, sizeof(buffer));
        
        if (bytes_received > 0) {
            printf("\nReceived data: %s", buffer);  // Example printout
        }
        
        // Close the socket connection
        call("SocketDLL.dll", "socket_close");
    } else {
        printf("\nFailed to connect to socket.");
    }
}


Explanation of the Zorro Script
call() Function: This function is used to call functions from the DLL in Zorro.
call("SocketDLL.dll", "socket_connect", "localhost", 65432) connects to the Python server running on localhost at port 65432.
call("SocketDLL.dll", "socket_send", data, sizeof(data)) sends the data array to the Python server.
call("SocketDLL.dll", "socket_receive", buffer, sizeof(buffer)) receives data from the server into the buffer.
call("SocketDLL.dll", "socket_close") closes the socket connection.
Python Socket Server to Receive Data from Zorro

Code
import socket

HOST = 'localhost'
PORT = 65432

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
print("Server listening...")

conn, addr = server.accept()
print(f"Connected by {addr}")

while True:
    data = conn.recv(1024)
    if not data:
        break
    print("Received data:", data)

    # Send response
    response = b"1"  # For example, send a '1' signal for buy
    conn.sendall(response)

conn.close()


One important note for all traders and programmers, As previously noted, we all want final solutions without having any bugs, scripts that are unlogical, and hard-to-understand code, but the whole point of these examples, it to learn to use ZorroGPT and find faster solutions for your imaginations.

Last edited by TipmyPip; 11/10/24 03:17.
Multi Agent DRL with Simple Stategy [Re: TipmyPip] #488432
11/10/24 10:36
11/10/24 10:36
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
To leverage Zorro Trader’s efficient, event-driven structure for managing a multi-agent Deep Reinforcement Learning (DRL) model setup, we can design the system to optimize computational speed and real-time trade execution while leaving the resource-intensive training to Python. Here’s an approach that maximizes Zorro's fast computation for managing multi-agent DRL models.

Key Principles for Zorro’s Role in Multi-Agent Management
Separation of Prediction and Training:

Zorro handles trade execution and prediction requests, which are computationally light and can run at high frequency.
The heavier tasks—training and tuning the DRL models—are handled by Python independently, reducing Zorro’s load and keeping trade execution highly responsive.
Socket Communication for Real-Time Data Transfer:

Zorro communicates with Python via a socket connection, sending real-time data for each agent and receiving predictions.
This eliminates I/O delays from file reads and writes, allowing Zorro to request predictions instantly and act on them immediately.
Dynamic and Concurrent Agent Management:

Zorro uses its fast computational ability to request predictions concurrently across multiple agents and assets.
It can trigger trade decisions for several agents in parallel, enabling highly responsive multi-asset or multi-strategy trading.
Implementation Strategy
Here’s how to set up Zorro to manage multiple agents effectively:

Zorro: Efficient, Concurrent Data Handling and Trade Execution
Python: Dedicated, Asynchronous Training with Real-Time Prediction Server
Step-by-Step Code Structure
1. Python Socket Server Code (Handling Multi-Agent Predictions and Training)
In Python, we set up a socket server that:

Listens for data requests from Zorro.
Uses pre-trained models to make quick predictions.
Runs training processes in the background asynchronously, ensuring it can respond to prediction requests without delay.

Code
import socket
import torch
import numpy as np
from model import TradingModel  # Assume TradingModel is defined appropriately

# Initialize models and load them if available
agents = {
    "EURUSD": TradingModel(input_size=5, hidden_layers=2, neurons_per_layer=64),
    "GBPUSD": TradingModel(input_size=5, hidden_layers=2, neurons_per_layer=64),
    "EURGBP": TradingModel(input_size=5, hidden_layers=2, neurons_per_layer=64)
}

for name, model in agents.items():
    try:
        model.load_state_dict(torch.load(f"{name}_model.pth"))
        model.eval()
    except FileNotFoundError:
        print(f"No saved model found for {name}, starting fresh.")

# Start a socket server to handle prediction requests
HOST = 'localhost'
PORT = 65432
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
print("Waiting for Zorro connection...")

conn, addr = server.accept()
print(f"Connected by {addr}")

while True:
    data = conn.recv(1024)
    if not data:
        break
    
    try:
        # Parse data to identify agent and extract feature inputs
        data_str = data.decode().split(',')
        agent_name = data_str[0]
        input_data = np.array(data_str[1:], dtype=np.float32)
        
        # Make a prediction if the agent exists
        if agent_name in agents:
            model = agents[agent_name]
            input_tensor = torch.tensor(input_data, dtype=torch.float32)
            with torch.no_grad():
                prediction = model(input_tensor).item()
            decision = '1' if prediction > 0.5 else '0'
        else:
            decision = '0'  # Default action if agent is unrecognized

        # Send the prediction decision back to Zorro
        conn.sendall(decision.encode())

    except Exception as e:
        print(f"Error processing request: {e}")
        break

conn.close()



2. Zorro Code with Socket Communication and Concurrent Agent Management
In Zorro, we:

Use a single socket_connect for each agent.
Request predictions concurrently and execute trades immediately after receiving each prediction.

Code
function run()
{
    // Define data feeds for each pair
    double EURUSD_Data[5] = { priceHigh(), priceLow(), priceClose(), priceOpen(), Vol() };
    double GBPUSD_Data[5] = { priceHigh(), priceLow(), priceClose(), priceOpen(), Vol() };
    double EURGBP_Data[5] = { priceHigh(), priceLow(), priceClose(), priceOpen(), Vol() };

    // Connect to Python server
    int socket = socket_connect("localhost", 65432);
    if (socket == 0) {
        printf("\nFailed to connect to Python socket.");
        return;
    }

    // Agent 1: EURUSD - Send data and get prediction
    string eurusd_data_str = strf("EURUSD,%f,%f,%f,%f,%f", EURUSD_Data[0], EURUSD_Data[1], EURUSD_Data[2], EURUSD_Data[3], EURUSD_Data[4]);
    socket_send(socket, eurusd_data_str, strlen(eurusd_data_str));
    char buffer[2];
    int bytes_received = socket_receive(socket, buffer, sizeof(buffer));
    if (bytes_received > 0 && buffer[0] == '1')
        enterLong("EURUSD");
    else
        enterShort("EURUSD");

    // Agent 2: GBPUSD - Send data and get prediction
    string gbpusd_data_str = strf("GBPUSD,%f,%f,%f,%f,%f", GBPUSD_Data[0], GBPUSD_Data[1], GBPUSD_Data[2], GBPUSD_Data[3], GBPUSD_Data[4]);
    socket_send(socket, gbpusd_data_str, strlen(gbpusd_data_str));
    bytes_received = socket_receive(socket, buffer, sizeof(buffer));
    if (bytes_received > 0 && buffer[0] == '1')
        enterLong("GBPUSD");
    else
        enterShort("GBPUSD");

    // Agent 3: EURGBP - Send data and get prediction
    string eurgbp_data_str = strf("EURGBP,%f,%f,%f,%f,%f", EURGBP_Data[0], EURGBP_Data[1], EURGBP_Data[2], EURGBP_Data[3], EURGBP_Data[4]);
    socket_send(socket, eurgbp_data_str, strlen(eurgbp_data_str));
    bytes_received = socket_receive(socket, buffer, sizeof(buffer));
    if (bytes_received > 0 && buffer[0] == '1')
        enterLong("EURGBP");
    else
        enterShort("EURGBP");

    // Close socket connection
    socket_close(socket);
}


Explanation of the Zorro Code
Concurrent Data Handling:

Zorro gathers data for each agent and sends it independently over the socket.
Each agent’s prediction is received immediately, and trades are executed without waiting for other predictions.
Direct Trade Execution:

Based on the prediction received from Python, Zorro immediately triggers a Long or Short position for each currency pair.
This approach leverages Zorro’s fast computation for rapid trade decisions, as the time-consuming training process is handled asynchronously by Python.
Benefits of This Setup
Parallel Prediction Requests:

Each agent’s data is processed individually, allowing predictions to be handled concurrently.
Zorro executes trades immediately, maximizing the benefit of fast computation.
Efficient Use of Resources:

Training is handled asynchronously by Python, while Zorro focuses purely on trade execution and prediction requests.
The socket communication enables real-time data exchange, ensuring Zorro’s high-frequency capabilities are fully utilized.
Scalable to More Agents:

Adding new agents is straightforward: simply expand the data gathering and prediction request handling sections in both Zorro and Python, as each agent operates independently in this setup.
By separating Zorro’s fast execution from Python’s computational load, this setup achieves efficient multi-agent management, ensuring real-time responsiveness and scalability.

Delta Dynamics [Re: TipmyPip] #488493
12/24/24 18:36
12/24/24 18:36
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
Sigma Matrix:

The Correlation Web
A web of nodes (N₁, N₂, ..., N₆) is interconnected, where each edge (Eᵢⱼ) between nodes Nᵢ and Nⱼ has a weight representing their correlation coefficient. The weights are given as follows:

| | N₁ | N₂ | N₃ | N₄ | N₅ | N₆ | |-------|------|------|------|------|------| | N₁ | 1.0 | 0.8 | 0.3 | 0.5 | 0.7 | 0.6 | | N₂ | 0.8 | 1.0 | 0.4 | 0.6 | 0.9 | 0.2 | | N₃ | 0.3 | 0.4 | 1.0 | 0.7 | 0.5 | 0.3 | | N₄ | 0.5 | 0.6 | 0.7 | 1.0 | 0.8 | 0.4 | | N₅ | 0.7 | 0.9 | 0.5 | 0.8 | 1.0 | 0.6 | | N₆ | 0.6 | 0.2 | 0.3 | 0.4 | 0.6 | 1.0 |

Your task:

Find the subset of nodes (clusters) such that the average weight of edges within each cluster is maximized.
Ensure that no node is part of more than one cluster.

Code
#define PAIRS 28 // Number of currency pairs

string CurrencyPairs[PAIRS] = {
    "EURUSD", "GBPUSD", "USDJPY", "GBPJPY", "USDCAD", "EURAUD", "EURJPY", 
    "AUDCAD", "AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "EURCAD", "EURCHF", 
    "EURGBP", "EURNZD", "GBPCAD", "GBPCHF", "NZDCAD", "NZDJPY", "NZDUSD", 
    "USDCHF", "CHFJPY", "AUDCHF", "GBPNZD", "NZDCHF", "CADCHF", "GBPAUD"
};

vars CorrelationMatrix[PAIRS][PAIRS]; // Correlation adjacency matrix
vars ArbitrageMatrix[PAIRS][PAIRS];  // Arbitrage adjacency matrix
int StateMatrix[PAIRS][3][3];        // Transition matrix for each pair
int LookBack = 200;                 // Lookback period for calculations

// Function to calculate correlation between two series
function calculateCorrelation(vars series1, vars series2, int len) {
    var mean1 = SMA(series1, len);
    var mean2 = SMA(series2, len);
    var numerator = 0, denom1 = 0, denom2 = 0;
    for (int i = 0; i < len; i++) {
        numerator += (series1[i] - mean1) * (series2[i] - mean2);
        denom1 += pow(series1[i] - mean1, 2);
        denom2 += pow(series2[i] - mean2, 2);
    }
    return numerator / sqrt(denom1 * denom2);
}

// Initialize the correlation network
function initializeCorrelationNetwork() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                vars series1 = series(price(CurrencyPairs[i]));
                vars series2 = series(price(CurrencyPairs[j]));
                CorrelationMatrix[i][j] = calculateCorrelation(series1, series2, LookBack);
            } else {
                CorrelationMatrix[i][j] = 1; // Self-correlation
            }
        }
    }
}

// Calculate arbitrage opportunities between pairs
function calculateArbitrage() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                ArbitrageMatrix[i][j] = log(price(CurrencyPairs[i]) / price(CurrencyPairs[j]));
            } else {
                ArbitrageMatrix[i][j] = 0; // No arbitrage within the same pair
            }
        }
    }
}

// Detect arbitrage cycles using a Bellman-Ford-like algorithm
function detectArbitrageCycles() {
    for (int k = 0; k < PAIRS; k++) {
        for (int i = 0; i < PAIRS; i++) {
            for (int j = 0; j < PAIRS; j++) {
                if (ArbitrageMatrix[i][k] + ArbitrageMatrix[k][j] < ArbitrageMatrix[i][j]) {
                    ArbitrageMatrix[i][j] = ArbitrageMatrix[i][k] + ArbitrageMatrix[k][j];
                }
            }
        }
    }
}

// Get the current market state for a currency pair
function getState(string pair) {
    var fastMA = SMA(series(price(pair)), 50);
    var slowMA = SMA(series(price(pair)), 200);
    if (fastMA > slowMA) return 1;  // Bull
    else if (fastMA < slowMA) return -1; // Bear
    return 0;  // Sideways
}

// Update the state transition matrix
function updateStateTransition(int pairIndex) {
    int currentState = getState(CurrencyPairs[pairIndex]);
    int lastState = StateMatrix[pairIndex][2]; // Store last state
    StateMatrix[pairIndex][lastState + 1][currentState + 1]++;
    StateMatrix[pairIndex][2] = currentState; // Update last state
}

// Main trading function
function run() {
    set(PLOTNOW);

    // Initialize networks
    initializeCorrelationNetwork();
    calculateArbitrage();

    // Update state transitions for each pair
    for (int i = 0; i < PAIRS; i++) {
        updateStateTransition(i);
    }

    // Example: Trade when arbitrage is detected
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (ArbitrageMatrix[i][j] > 0.01) { // Arbitrage threshold
                enterLong(CurrencyPairs[i]);
                enterShort(CurrencyPairs[j]);
            }
        }
    }
}

Delta Cycle Dynamics [Re: TipmyPip] #488494
12/24/24 18:40
12/24/24 18:40
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
Arbitrage Cycle Mystery
Imagine a trading system with 5 currency pairs (P₁, P₂, P₃, P₄, P₅). Each pair has a profit factor (PFᵢⱼ) when moving from pair Pᵢ to pair Pⱼ. The profit factors are given in a directed graph:

P₁ → P₂: 1.2 P₂ → P₁: 0.8
P₁ → P₃: 1.1 P₃ → P₁: 0.9
P₂ → P₃: 1.3 P₃ → P₂: 0.7
P₄ → P₁: 1.5 P₁ → P₄: 0.6
P₄ → P₃: 1.4 P₃ → P₄: 0.8
P₅ → P₄: 1.2 P₄ → P₅: 0.9
P₅ → P₃: 1.1 P₃ → P₅: 0.8

Your task:

Find the cycle of pairs that maximizes the product of profit factors (PF₁ × PF₂ × PF₃ × ...).
Ensure the cycle returns to the starting pair.


Code
#define PAIRS 28 // Number of currency pairs

string CurrencyPairs[PAIRS] = {
    "EURUSD", "GBPUSD", "USDJPY", "GBPJPY", "USDCAD", "EURAUD", "EURJPY", 
    "AUDCAD", "AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "EURCAD", "EURCHF", 
    "EURGBP", "EURNZD", "GBPCAD", "GBPCHF", "NZDCAD", "NZDJPY", "NZDUSD", 
    "USDCHF", "CHFJPY", "AUDCHF", "GBPNZD", "NZDCHF", "CADCHF", "GBPAUD"
};

vars CorrelationMatrix[PAIRS][PAIRS]; // Correlation adjacency matrix
vars ArbitrageMatrix[PAIRS][PAIRS];  // Arbitrage adjacency matrix
vars RiskMatrix[PAIRS];             // Risk matrix for each pair (e.g., volatility)
int StateMatrix[PAIRS][3][3];       // Transition matrix for each pair
vars PortfolioWeights[PAIRS];       // Optimized portfolio weights
int LookBack = 200;                 // Lookback period for calculations

// Function to calculate correlation between two series
function calculateCorrelation(vars series1, vars series2, int len) {
    var mean1 = SMA(series1, len);
    var mean2 = SMA(series2, len);
    var numerator = 0, denom1 = 0, denom2 = 0;
    for (int i = 0; i < len; i++) {
        numerator += (series1[i] - mean1) * (series2[i] - mean2);
        denom1 += pow(series1[i] - mean1, 2);
        denom2 += pow(series2[i] - mean2, 2);
    }
    return numerator / sqrt(denom1 * denom2);
}

// Initialize the correlation network
function initializeCorrelationNetwork() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                vars series1 = series(price(CurrencyPairs[i]));
                vars series2 = series(price(CurrencyPairs[j]));
                CorrelationMatrix[i][j] = calculateCorrelation(series1, series2, LookBack);
            } else {
                CorrelationMatrix[i][j] = 1; // Self-correlation
            }
        }
    }
}

// Calculate arbitrage opportunities between pairs
function calculateArbitrage() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                ArbitrageMatrix[i][j] = log(price(CurrencyPairs[i]) / price(CurrencyPairs[j]));
            } else {
                ArbitrageMatrix[i][j] = 0; // No arbitrage within the same pair
            }
        }
    }
}

// Calculate risk for each pair (volatility-based)
function calculateRiskMatrix() {
    for (int i = 0; i < PAIRS; i++) {
        RiskMatrix[i] = StdDev(series(price(CurrencyPairs[i])), LookBack);
    }
}

// Optimize portfolio weights based on risk and correlation
function optimizePortfolio() {
    var TotalWeight = 0;
    for (int i = 0; i < PAIRS; i++) {
        PortfolioWeights[i] = 1 / RiskMatrix[i]; // Risk-based weighting
        TotalWeight += PortfolioWeights[i];
    }
    for (int i = 0; i < PAIRS; i++) {
        PortfolioWeights[i] /= TotalWeight; // Normalize weights
    }
}

// Detect arbitrage cycles using a Bellman-Ford-like algorithm
function detectArbitrageCycles() {
    for (int k = 0; k < PAIRS; k++) {
        for (int i = 0; i < PAIRS; i++) {
            for (int j = 0; j < PAIRS; j++) {
                if (ArbitrageMatrix[i][k] + ArbitrageMatrix[k][j] < ArbitrageMatrix[i][j]) {
                    ArbitrageMatrix[i][j] = ArbitrageMatrix[i][k] + ArbitrageMatrix[k][j];
                }
            }
        }
    }
}

// Get the current market state for a currency pair
function getState(string pair) {
    var fastMA = SMA(series(price(pair)), 50);
    var slowMA = SMA(series(price(pair)), 200);
    if (fastMA > slowMA) return 1;  // Bull
    else if (fastMA < slowMA) return -1; // Bear
    return 0;  // Sideways
}

// Update the state transition matrix
function updateStateTransition(int pairIndex) {
    int currentState = getState(CurrencyPairs[pairIndex]);
    int lastState = StateMatrix[pairIndex][2]; // Store last state
    StateMatrix[pairIndex][lastState + 1][currentState + 1]++;
    StateMatrix[pairIndex][2] = currentState; // Update last state
}

// Execute trades based on portfolio weights and arbitrage opportunities
function executeTrades() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (ArbitrageMatrix[i][j] > 0.01) { // Arbitrage threshold
                var WeightI = PortfolioWeights[i];
                var WeightJ = PortfolioWeights[j];
                enterLong(CurrencyPairs[i], WeightI);  // Weighted trade
                enterShort(CurrencyPairs[j], WeightJ); // Weighted trade
            }
        }
    }
}

// Main trading function
function run() {
    set(PLOTNOW);

    // Initialize all networks and matrices
    initializeCorrelationNetwork();
    calculateArbitrage();
    calculateRiskMatrix();
    optimizePortfolio();

    // Update state transitions for each pair
    for (int i = 0; i < PAIRS; i++) {
        updateStateTransition(i);
    }

    // Execute trades based on analysis
    executeTrades();
}

Last edited by TipmyPip; 12/24/24 18:43.
Σ Φ - Δ Ξ (t), Σ Φ Δ Ξ (∫f(τ)dτ) [Re: TipmyPip] #488495
12/24/24 19:47
12/24/24 19:47
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
The Weighted Dynamic Arbitrage Graph

You are given a directed weighted graph 𝐺=(𝑉,𝐸) where: 𝑉 represents currency pairs (e.g., EURUSD, GBPUSD, etc.).
𝐸 represents the relationships between the currency pairs (e.g., price ratios, arbitrage opportunities).
Each edge 𝑒(𝑖,𝑗) between nodes 𝑣𝑖 and 𝑣𝑗 has a weight 𝑤(𝑖,𝑗) representing the logarithm of the price ratio between
𝑣𝑖 and 𝑣𝑗.

Problem:
The graph 𝐺 is time-dependent. At each time step 𝑡, the edge weights 𝑤(𝑖,𝑗,𝑡) change according to a function:

𝑤(𝑖,𝑗,𝑡) = log(𝑃𝑖(𝑡)𝑃𝑗(𝑡))−Δ(𝑖,𝑗,𝑡) where: 𝑃𝑖(𝑡) and 𝑃𝑗(𝑡) are the prices of 𝑣𝑖 and 𝑣𝑗 at time 𝑡. Δ(𝑖,𝑗,𝑡) is a dynamic threshold, influenced by volatility.
A negative weight cycle in 𝐺 represents an arbitrage opportunity, where the product of the weights along the cycle is greater than

1: ∏(𝑖,𝑗)∈𝐶𝑒𝑤(𝑖,𝑗,𝑡)>1.

Your goal is to: Identify all negative weight cycles in 𝐺 for 𝑡1 ≤ 𝑡 ≤𝑡2 .

For each negative cycle 𝐶, calculate the maximum profit factor:

Profit(𝐶)=∏(𝑖,𝑗)∈𝐶𝑒𝑤(𝑖,𝑗,𝑡).

Find the most profitable cycle across all time steps 𝑡.

Additional Constraints:

The graph 𝐺 has ∣𝑉∣=28 nodes (one for each currency pair) and ∣𝐸∣=∣𝑉∣×(∣𝑉∣−1)
∣E∣=∣V∣×(∣V∣−1) edges (fully connected directed graph).

Edge weights 𝑤(𝑖,𝑗,𝑡) vary dynamically with 𝑡 according to: Δ(𝑖,𝑗,𝑡)=𝜎𝑖(𝑡)⋅𝜎𝑗(𝑡), where

𝜎𝑖(𝑡) is the standard deviation of prices for 𝑣𝑖 over a rolling window of 20 time steps.

You must use an efficient algorithm (e.g., Bellman-Ford for detecting negative cycles) to handle the graph's dynamic nature.


Code
#define PAIRS 28 // Number of currency pairs

string CurrencyPairs[PAIRS] = {
    "EURUSD", "GBPUSD", "USDJPY", "GBPJPY", "USDCAD", "EURAUD", "EURJPY", 
    "AUDCAD", "AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "EURCAD", "EURCHF", 
    "EURGBP", "EURNZD", "GBPCAD", "GBPCHF", "NZDCAD", "NZDJPY", "NZDUSD", 
    "USDCHF", "CHFJPY", "AUDCHF", "GBPNZD", "NZDCHF", "CADCHF", "GBPAUD"
};

vars CorrelationMatrix[PAIRS][PAIRS];    // Correlation adjacency matrix
vars ArbitrageMatrix[PAIRS][PAIRS];     // Arbitrage adjacency matrix
vars VolatilityMatrix[PAIRS];           // Volatility levels for each pair
vars DynamicThresholdMatrix[PAIRS][PAIRS]; // Dynamic arbitrage thresholds
vars RiskAdjustedWeights[PAIRS];        // Risk-adjusted portfolio weights
int StateMatrix[PAIRS][3][3];           // Transition matrix for each pair
vars CurrentDrawdown;                   // Current drawdown level
int LookBack = 200;                     // Lookback period for calculations

// Function to calculate correlation between two series
function calculateCorrelation(vars series1, vars series2, int len) {
    var mean1 = SMA(series1, len);
    var mean2 = SMA(series2, len);
    var numerator = 0, denom1 = 0, denom2 = 0;
    for (int i = 0; i < len; i++) {
        numerator += (series1[i] - mean1) * (series2[i] - mean2);
        denom1 += pow(series1[i] - mean1, 2);
        denom2 += pow(series2[i] - mean2, 2);
    }
    return numerator / sqrt(denom1 * denom2);
}

// Initialize the correlation network
function initializeCorrelationNetwork() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                vars series1 = series(price(CurrencyPairs[i]));
                vars series2 = series(price(CurrencyPairs[j]));
                CorrelationMatrix[i][j] = calculateCorrelation(series1, series2, LookBack);
            } else {
                CorrelationMatrix[i][j] = 1; // Self-correlation
            }
        }
    }
}

// Calculate arbitrage opportunities between pairs with dynamic thresholds
function calculateDynamicArbitrage() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                var priceRatio = log(price(CurrencyPairs[i]) / price(CurrencyPairs[j]));
                var threshold = max(0.01, VolatilityMatrix[i] * 0.5); // Dynamic threshold
                DynamicThresholdMatrix[i][j] = threshold;
                ArbitrageMatrix[i][j] = (abs(priceRatio) > threshold) ? priceRatio : 0;
            } else {
                ArbitrageMatrix[i][j] = 0; // No arbitrage within the same pair
            }
        }
    }
}

// Calculate volatility levels for each pair
function calculateVolatilityMatrix() {
    for (int i = 0; i < PAIRS; i++) {
        VolatilityMatrix[i] = StdDev(series(price(CurrencyPairs[i])), LookBack);
    }
}

// Risk adjustment based on drawdown and portfolio composition
function adjustRiskWeights() {
    var TotalWeight = 0;
    for (int i = 0; i < PAIRS; i++) {
        var riskFactor = max(0.1, 1 - CurrentDrawdown / 0.2); // Reduce risk if drawdown exceeds 20%
        RiskAdjustedWeights[i] = (1 / VolatilityMatrix[i]) * riskFactor;
        TotalWeight += RiskAdjustedWeights[i];
    }
    for (int i = 0; i < PAIRS; i++) {
        RiskAdjustedWeights[i] /= TotalWeight; // Normalize weights
    }
}

// Execute trades based on dynamic arbitrage and risk-adjusted weights
function executeDynamicTrades() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (ArbitrageMatrix[i][j] != 0) {
                var WeightI = RiskAdjustedWeights[i];
                var WeightJ = RiskAdjustedWeights[j];
                if (ArbitrageMatrix[i][j] > 0) { // Long-Short arbitrage
                    enterLong(CurrencyPairs[i], WeightI);
                    enterShort(CurrencyPairs[j], WeightJ);
                } else if (ArbitrageMatrix[i][j] < 0) { // Short-Long arbitrage
                    enterShort(CurrencyPairs[i], WeightI);
                    enterLong(CurrencyPairs[j], WeightJ);
                }
            }
        }
    }
}

// Track drawdown levels
function monitorDrawdown() {
    CurrentDrawdown = max(0, 1 - (Equity / MaxEquity));
    if (CurrentDrawdown > 0.2) { // Emergency shutdown at 20% drawdown
        exitLong();
        exitShort();
        printf("Emergency risk controls triggered. All positions closed.");
    }
}

// Main trading function
function run() {
    set(PLOTNOW);

    // Update and calculate all matrices
    initializeCorrelationNetwork();
    calculateVolatilityMatrix();
    calculateDynamicArbitrage();
    adjustRiskWeights();
    monitorDrawdown();

    // Execute trades based on advanced analysis
    executeDynamicTrades();
}

Last edited by TipmyPip; 12/24/24 20:39.
Profit Path Conundrum [Re: TipmyPip] #488496
12/25/24 14:23
12/25/24 14:23
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
Algorithm Complexity
You are tasked with assessing the efficiency of the trading algorithm.

Scenario
The algorithm evaluates all possible trade paths across 𝑃𝐴𝐼𝑅𝑆 currency pairs to identify the most profitable path. Each path must satisfy a profitability threshold that is adjusted dynamically based on real-time performance. Trades are executed only when the risk-adjusted profit surpasses the threshold. The system operates continuously, recalculating profitability every second.

Challenge Questions

Graph Analysis:

Given 𝑃𝐴𝐼𝑅𝑆=28, the graph has ∣𝑉∣=28 vertices. How many edges ∣𝐸∣ exist in this graph if all trades are considered? Assume the graph is fully connected but excludes self-loops.

Path Complexity:

How many possible paths can exist from a source currency pair 𝐶𝑠 to a target pair 𝐶𝑒 if loops and revisits are allowed?
Bellman-Ford Complexity:

The Bellman-Ford algorithm iterates over all edges ∣𝐸∣ for ∣𝑉∣−1 rounds. Calculate the total computational complexity in terms of ∣𝑉∣ and ∣𝐸∣. Dynamic Threshold Adjustment:

If the threshold Δ is recalculated using volatility data for each currency pair and there are 50 price data points per pair, what is the time complexity of the threshold update process?

Scalability:

If 𝑃𝐴𝐼𝑅𝑆 increases to 56, describe how the computational complexity changes for: Profitability matrix calculation. Bellman-Ford algorithm. Dynamic threshold adjustment. Real-Time Execution:

Assume profitability recalculations are triggered every second. What is the expected latency for processing
𝑃𝐴𝐼𝑅𝑆= 28 if the system can handle 100,000 operations per second?


Code
#define PAIRS 28 // Number of currency pairs

string CurrencyPairs[PAIRS] = {
    "EURUSD", "GBPUSD", "USDJPY", "GBPJPY", "USDCAD", "EURAUD", "EURJPY", 
    "AUDCAD", "AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "EURCAD", "EURCHF", 
    "EURGBP", "EURNZD", "GBPCAD", "GBPCHF", "NZDCAD", "NZDJPY", "NZDUSD", 
    "USDCHF", "CHFJPY", "AUDCHF", "GBPNZD", "NZDCHF", "CADCHF", "GBPAUD"
};

vars ProfitMatrix[PAIRS][PAIRS]; // Edge weights (profitability)
int Previous[PAIRS];            // Stores the previous node in the path
vars PathProfit[PAIRS];         // Stores cumulative profit along the path
vars DynamicDeltaThreshold;     // Dynamic threshold to execute trades

// Function to calculate profitability matrix
function calculateProfitMatrix() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                var priceRatio = price(CurrencyPairs[i]) / price(CurrencyPairs[j]);
                ProfitMatrix[i][j] = log(priceRatio); // Logarithmic profitability
            } else {
                ProfitMatrix[i][j] = 0; // No self-loop
            }
        }
    }
}

// Calculate the Dynamic Delta Threshold with risk-adjustment and feedback
function calculateDynamicDeltaThreshold() {
    var totalRiskAdjustedProfit = 0;
    int count = 0;

    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j && ProfitMatrix[i][j] > 0) {
                var volatility = StdDev(series(price(CurrencyPairs[i])), 50); // 50-period volatility
                var riskAdjustedProfit = ProfitMatrix[i][j] / volatility; // Risk-adjusted profit
                totalRiskAdjustedProfit += riskAdjustedProfit;
                count++;
            }
        }
    }

    if (count > 0) {
        var baselineThreshold = totalRiskAdjustedProfit / count; // Average risk-adjusted profit
        var performanceFactor = Equity / MaxEquity; // Performance feedback
        DynamicDeltaThreshold = baselineThreshold * performanceFactor; // Adjust threshold dynamically
    } else {
        DynamicDeltaThreshold = 0.001; // Default fallback
    }

    // Log the threshold for backtesting and analysis
    printf("DynamicDeltaThreshold: %.6f\n", DynamicDeltaThreshold);
}

// Bellman-Ford algorithm to find paths with the highest cumulative profit
function bellmanFord(int start) {
    for (int i = 0; i < PAIRS; i++) {
        PathProfit[i] = -1e10; // Negative infinity for unvisited nodes
        Previous[i] = -1;     // No predecessor
    }
    PathProfit[start] = 0; // Profit starts at 0 from the source

    for (int k = 0; k < PAIRS - 1; k++) {
        for (int i = 0; i < PAIRS; i++) {
            for (int j = 0; j < PAIRS; j++) {
                if (ProfitMatrix[i][j] != 0 && PathProfit[i] + ProfitMatrix[i][j] > PathProfit[j]) {
                    PathProfit[j] = PathProfit[i] + ProfitMatrix[i][j]; // Update cumulative profit
                    Previous[j] = i; // Track the path
                }
            }
        }
    }
}

// Execute trades along the highest cumulative profit path
function executePath(int start, int end) {
    int current = end;

    while (current != -1) {
        int previous = Previous[current];
        if (previous == -1) break;

        if (ProfitMatrix[previous][current] > 0) {
            enterLong(CurrencyPairs[previous]);
            enterShort(CurrencyPairs[current]);
        } else {
            enterShort(CurrencyPairs[previous]);
            enterLong(CurrencyPairs[current]);
        }

        current = previous;
    }
}

// Continuously execute trades while conditions exist
function executeContinuousTrades(int start) {
    while (1) {
        calculateProfitMatrix();          // Update the graph with live data
        calculateDynamicDeltaThreshold(); // Adjust the threshold dynamically
        bellmanFord(start);               // Recalculate paths with the highest cumulative profit

        for (int i = 0; i < PAIRS; i++) {
            for (int j = 0; j < PAIRS; j++) {
                if (i != j && ProfitMatrix[i][j] > DynamicDeltaThreshold) {
                    enterLong(CurrencyPairs[i]);
                    enterShort(CurrencyPairs[j]);
                    printf("Executing Trade: Long %s, Short %s\n", CurrencyPairs[i], CurrencyPairs[j]);
                }
            }
        }

        // Add a condition to exit the loop for backtesting or analysis
        if (isBacktest() && getBacktestPeriod() == "End") {
            break;
        }
    }
}

// Main trading function
function run() {
    set(PLOTNOW);
    int startPair = 0; // Start from the first currency pair

    executeContinuousTrades(startPair);
}

Stochastic Correlation in Currency Pairs [Re: TipmyPip] #488497
12/25/24 15:34
12/25/24 15:34
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
Optimal Arbitrage with Stochastic Correlation in Currency Pairs
You are tasked with developing an arbitrage strategy between three independent currency pairs:
𝐴/𝐵, 𝐵/𝐶, and 𝐴/𝐶, where:

The price of each currency pair follows a geometric Brownian motion:

dS_i = μ_i * S_i * dt + σ_i * S_i * dW_i, for i ∈ {1, 2, 3}

μ_i: Drift rate of the 𝑖-th pair.
σ_i: Volatility of the 𝑖-th pair.
W_i: Independent Wiener processes for each pair.
A stochastic correlation ρ(t) governs the dependency between the pairs' volatilities:

dρ(t) = κ * (θ - ρ(t)) * dt + η * √(1 - ρ(t)^2) * dZ_t
κ: Mean-reversion speed of ρ(t).
θ: Long-term mean of ρ(t).
η: Volatility of ρ(t).
Z_t: Another Wiener process, independent of W_i.

Objective
Derive a dynamic arbitrage strategy that:

Exploits triangular arbitrage opportunities between the three currency pairs.
Incorporates stochastic correlation ρ(t) to optimize trading decisions.
The profit at each step is calculated as:

Profit = log(S_AB * S_BC / S_AC)

When Profit > Δ, execute arbitrage trades.
Δ: Dynamic threshold dependent on ρ(t).

Formulate the optimal stopping problem:

Define the time Ï„ to execute trades based on maximizing expected profit:

V(S, ρ) = sup_τ E [ ∫_0^τ Profit(S, ρ) * e^(-r * t) dt ]

r: Risk-free discount rate.


Code
#define PAIRS 28 // Number of currency pairs

string CurrencyPairs[PAIRS] = {
    "EURUSD", "GBPUSD", "USDJPY", "GBPJPY", "USDCAD", "EURAUD", "EURJPY", 
    "AUDCAD", "AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "EURCAD", "EURCHF", 
    "EURGBP", "EURNZD", "GBPCAD", "GBPCHF", "NZDCAD", "NZDJPY", "NZDUSD", 
    "USDCHF", "CHFJPY", "AUDCHF", "GBPNZD", "NZDCHF", "CADCHF", "GBPAUD"
};

vars ProfitMatrix[PAIRS][PAIRS];  // Profitability matrix
int Previous[PAIRS];             // Tracks the previous node in the path
vars PathProfit[PAIRS];          // Cumulative profit along the path
vars DynamicDeltaThreshold;      // Dynamic threshold for trade execution

var thresholdZ = 2;              // Z-score threshold
var volatilityThreshold = 1;     // Relative volatility threshold
int lookback = 50;               // Lookback period for mean and volatility

// Function to calculate profitability matrix
function calculateProfitMatrix() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                // Calculate price ratio and mean reversion metrics
                var priceRatio = price(CurrencyPairs[i]) / price(CurrencyPairs[j]);
                var mean = SMA(series(price(CurrencyPairs[i])), lookback);
                var zScore = (price(CurrencyPairs[i]) - mean) / StdDev(series(price(CurrencyPairs[i])), lookback);
                var volatility = StdDev(series(price(CurrencyPairs[i])), lookback);
                var relativeVolatility = volatility / SMA(series(volatility), lookback);

                // Filter trades based on Z-score and volatility
                if (abs(zScore) > thresholdZ && relativeVolatility > volatilityThreshold) {
                    ProfitMatrix[i][j] = log(priceRatio) - (DynamicDeltaThreshold / volatility);
                } else {
                    ProfitMatrix[i][j] = -INF; // Disqualify trade
                }
            } else {
                ProfitMatrix[i][j] = 0; // No self-loops
            }
        }
    }
}

// Calculate the dynamic delta threshold with risk-adjustment
function calculateDynamicDeltaThreshold() {
    var totalRiskAdjustedProfit = 0;
    int count = 0;

    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j && ProfitMatrix[i][j] > -INF) {
                var volatility = StdDev(series(price(CurrencyPairs[i])), lookback);
                var riskAdjustedProfit = ProfitMatrix[i][j] / volatility;
                totalRiskAdjustedProfit += riskAdjustedProfit;
                count++;
            }
        }
    }

    if (count > 0) {
        var baselineThreshold = totalRiskAdjustedProfit / count; // Average risk-adjusted profit
        var performanceFactor = Equity / MaxEquity; // Performance feedback
        DynamicDeltaThreshold = baselineThreshold * performanceFactor; // Adjust threshold dynamically
    } else {
        DynamicDeltaThreshold = 0.001; // Default fallback
    }
}

// Bellman-Ford algorithm to find paths with the highest cumulative profit
function bellmanFord(int start) {
    for (int i = 0; i < PAIRS; i++) {
        PathProfit[i] = -INF; // Negative infinity for unvisited nodes
        Previous[i] = -1;     // No predecessor
    }
    PathProfit[start] = 0; // Profit starts at 0 from the source

    for (int k = 0; k < PAIRS - 1; k++) {
        for (int i = 0; i < PAIRS; i++) {
            for (int j = 0; j < PAIRS; j++) {
                if (ProfitMatrix[i][j] != -INF && PathProfit[i] + ProfitMatrix[i][j] > PathProfit[j]) {
                    PathProfit[j] = PathProfit[i] + ProfitMatrix[i][j]; // Update cumulative profit
                    Previous[j] = i; // Track the path
                }
            }
        }
    }
}

// Execute trades along the highest cumulative profit path
function executePath(int start, int end) {
    int current = end;

    while (current != -1) {
        int prev = Previous[current];
        if (prev == -1) break;

        if (ProfitMatrix[prev][current] > 0) {
            enterLong(CurrencyPairs[prev]);
            enterShort(CurrencyPairs[current]);
        } else {
            enterShort(CurrencyPairs[prev]);
            enterLong(CurrencyPairs[current]);
        }

        current = prev;
    }
}

// Continuously execute trades while conditions exist
function executeContinuousTrades(int start) {
    while (1) {
        calculateProfitMatrix();          // Update the graph with live data
        calculateDynamicDeltaThreshold(); // Adjust the threshold dynamically
        bellmanFord(start);               // Recalculate paths with the highest cumulative profit

        for (int i = 0; i < PAIRS; i++) {
            for (int j = 0; j < PAIRS; j++) {
                if (i != j && ProfitMatrix[i][j] > DynamicDeltaThreshold) {
                    enterLong(CurrencyPairs[i]);
                    enterShort(CurrencyPairs[j]);
                    printf("Executing Trade: Long %s, Short %s\n", CurrencyPairs[i], CurrencyPairs[j]);
                }
            }
        }

        // Add a condition to exit the loop for backtesting or analysis
        if (isBacktest() && getBacktestPeriod() == "End") {
            break;
        }
    }
}

// Main trading function
function run() {
    set(PLOTNOW);
    int startPair = 0; // Start from the first currency pair

    executeContinuousTrades(startPair);
}

Last edited by TipmyPip; 12/25/24 15:58.
PCA and Stochastic Volatility [Re: TipmyPip] #488498
12/25/24 17:43
12/25/24 17:43
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
Dynamic Trading Strategy with PCA and Stochastic Volatility

You are tasked with designing an optimal dynamic trading strategy that exploits volatility patterns across multiple currency pairs. This strategy incorporates Principal Component Analysis (PCA) for dimensionality reduction and Stochastic Calculus to model the evolving market dynamics.

Setup

Currency Pairs and Volatility Dynamics:

Let X_t = [X_1(t), X_2(t), ..., X_n(t)] represent the instantaneous volatility spreads of n currency pairs at time t.
Each volatility spread X_i(t) evolves according to a stochastic differential equation (SDE):

dX_i(t) = mu_i * dt + sigma_i * dW_i(t),

where:
mu_i is the drift of the volatility spread (mean reversion to long-term volatility).
sigma_i is the volatility of the volatility spread (vol of vol).
W_i(t) is an independent Wiener process for each pair.

Principal Component Analysis (PCA):

At each time step, perform PCA on the volatility matrix to identify the top k principal components (k <= n).
The components are represented as:

Y_t = V * X_t,

where:
V is the matrix of eigenvectors (PCA transformation matrix).
Y_t contains the transformed coordinates in the reduced-dimensional space.

Profitability Metric:

Define the profitability of a trading path between two currency pairs based on the PCA-reduced volatility data:

Profit(i, j) = integral from t0 to t1 [ log(Y_i(t) / Y_j(t)) * dt ],
where Y_i(t) and Y_j(t) are the PCA components of the respective pairs.

The Puzzle

Stochastic Optimization:

Given n = 28 currency pairs, model the system of volatility spreads X_t using PCA and stochastic differential equations.
Derive a strategy to maximize the expected cumulative profitability:

E [ integral from t0 to t1 [ Profit(i, j) * dt ] ],
where Profit(i, j) depends on the PCA-reduced volatility spreads.

Constraints:

The number of components k must be optimized dynamically to ensure at least 90% of the variance is captured:

sum from i=1 to k [ lambda_i ] / sum from i=1 to n [ lambda_i ] >= 0.90,

where lambda_i are the eigenvalues of the covariance matrix.
The strategy must account for transaction costs proportional to the change in position:

Cost = c * abs(Delta_Position),

where c is the transaction cost coefficient.

Optimal Stopping:

Identify the optimal stopping time tau to rebalance the portfolio by solving the following stochastic control problem:

V(X_t) = sup_tau E [ integral from t to tau [ Profit(i, j) * exp(-r * (s - t)) * ds ] - Cost(tau) ], where r is the risk-free discount rate.

Questions to Solve

Variance Threshold:

At each time step, determine the optimal number of components k such that:

sum from i=1 to k [ lambda_i ] / sum from i=1 to n [ lambda_i ] >= 0.90, where lambda_i are the eigenvalues of the covariance matrix.

Stochastic Path Simulation:

Simulate the paths of X_t and Y_t for 28 currency pairs over a period [t0, t1].
How do the principal components evolve over time?

Profitability Surface:

Compute the profitability for all pairwise combinations of (i, j) and identify the most profitable trading path over [t0, t1].

Optimal Rebalancing:

Solve the optimal stopping problem to determine when to rebalance the portfolio to maximize net profitability.


Code
#define PAIRS 28 // Number of currency pairs

string CurrencyPairs[PAIRS] = {
    "EURUSD", "GBPUSD", "USDJPY", "GBPJPY", "USDCAD", "EURAUD", "EURJPY",
    "AUDCAD", "AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "EURCAD", "EURCHF",
    "EURGBP", "EURNZD", "GBPCAD", "GBPCHF", "NZDCAD", "NZDJPY", "NZDUSD",
    "USDCHF", "CHFJPY", "AUDCHF", "GBPNZD", "NZDCHF", "CADCHF", "GBPAUD"
};

vars VolatilityMatrix[PAIRS][PAIRS];  // Volatility relationship matrix
vars CovMatrix[PAIRS][PAIRS];        // Covariance matrix
vars Eigenvalues[PAIRS];             // Eigenvalues from PCA
vars Eigenvectors[PAIRS][PAIRS];     // Eigenvectors from PCA
vars volatilities[PAIRS];            // Volatility for each pair
vars ReducedMatrix[PAIRS][PAIRS];    // Reduced matrix for all components
int lookback = 50;                   // Lookback period for volatility calculation

// Function to calculate volatilities for all pairs
function calculateVolatilities() {
    for (int i = 0; i < PAIRS; i++) {
        volatilities[i] = StdDev(series(price(CurrencyPairs[i])), lookback);
    }
}

// Function to calculate the volatility matrix (volatility spreads)
function calculateVolatilityMatrix() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            if (i != j) {
                VolatilityMatrix[i][j] = volatilities[i] - volatilities[j];
            } else {
                VolatilityMatrix[i][j] = 0; // Self-loops have no effect
            }
        }
    }
}

// Calculate the covariance between two series of data
function covariance(vars series1, vars series2, int length) {
    var mean1 = 0, mean2 = 0, cov = 0;

    // Step 1: Compute the means of both series
    for (int i = 0; i < length; i++) {
        mean1 += series1[i];
        mean2 += series2[i];
    }
    mean1 /= length;
    mean2 /= length;

    // Step 2: Compute the covariance
    for (int i = 0; i < length; i++) {
        cov += (series1[i] - mean1) * (series2[i] - mean2);
    }

    return cov / length;
}

// Function to calculate the covariance matrix
function calculateCovarianceMatrix() {
    int length = PAIRS; // Length of the series (number of pairs)
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            CovMatrix[i][j] = covariance(VolatilityMatrix[i], VolatilityMatrix[j], length);
        }
    }
}

// Perform PCA: Decompose the covariance matrix into eigenvalues and eigenvectors
function performPCA() {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < PAIRS; j++) {
            Eigenvectors[i][j] = CovMatrix[i][j]; // Initialize with CovMatrix for decomposition
        }
    }

    // Perform power iteration or similar numerical eigenvalue decomposition
    for (int i = 0; i < PAIRS; i++) {
        Eigenvalues[i] = 0;
        for (int j = 0; j < PAIRS; j++) {
            Eigenvalues[i] += Eigenvectors[i][j] * Eigenvectors[i][j];
        }
        Eigenvalues[i] = sqrt(Eigenvalues[i]); // Compute the eigenvalue magnitude
    }

    // Sort eigenvalues and eigenvectors by descending eigenvalue order
    for (int i = 0; i < PAIRS - 1; i++) {
        for (int j = i + 1; j < PAIRS; j++) {
            if (Eigenvalues[i] < Eigenvalues[j]) {
                // Swap eigenvalues
                var tempValue = Eigenvalues[i];
                Eigenvalues[i] = Eigenvalues[j];
                Eigenvalues[j] = tempValue;

                // Swap eigenvectors
                for (int k = 0; k < PAIRS; k++) {
                    var tempVector = Eigenvectors[k][i];
                    Eigenvectors[k][i] = Eigenvectors[k][j];
                    Eigenvectors[k][j] = tempVector;
                }
            }
        }
    }
}

// Determine the optimal number of components based on cumulative variance explained
function optimizeComponents(vars Eigenvalues, int totalComponents, var targetVariance) {
    var totalVariance = 0;
    for (int i = 0; i < totalComponents; i++) {
        totalVariance += Eigenvalues[i];
    }

    var cumulativeVariance = 0;
    for (int i = 0; i < totalComponents; i++) {
        cumulativeVariance += Eigenvalues[i];
        if (cumulativeVariance / totalVariance >= targetVariance) { // Target variance explained
            return i + 1; // Return the optimal number of components
        }
    }
    return totalComponents; // Default to all components
}

// Project the volatility matrix onto the top principal components
function reduceMatrix(int topComponents) {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < topComponents; j++) {
            ReducedMatrix[i][j] = dotProduct(VolatilityMatrix[i], Eigenvectors[j]);
        }
    }
}

// Trade logic based on PCA-reduced components
function tradeWithPCA(int topComponents, var threshold) {
    for (int i = 0; i < PAIRS; i++) {
        for (int j = 0; j < topComponents; j++) {
            if (abs(ReducedMatrix[i][j]) > threshold) {
                if (ReducedMatrix[i][j] > 0) {
                    enterLong(CurrencyPairs[i]);
                } else {
                    enterShort(CurrencyPairs[i]);
                }
            }
        }
    }
}

// Main trading function
function run() {
    set(PLOTNOW);

    calculateVolatilities();          // Step 1: Calculate volatilities
    calculateVolatilityMatrix();      // Step 2: Compute volatility matrix
    calculateCovarianceMatrix();      // Step 3: Compute covariance matrix
    performPCA();                     // Step 4: Perform PCA

    // Optimize the number of components based on 90% variance explained
    int optimalComponents = optimizeComponents(Eigenvalues, PAIRS, 0.90);

    // Reduce the matrix using the optimal number of components
    reduceMatrix(optimalComponents);

    // Trade using PCA-reduced features
    var threshold = 0.05; // Set a trading threshold
    tradeWithPCA(optimalComponents, threshold);
}

Re: PCA and Stochastic Volatility [Re: TipmyPip] #488508
01/02/25 06:37
01/02/25 06:37
Joined: Apr 2023
Posts: 56
V
vicknick Offline
Junior Member
vicknick  Offline
Junior Member
V

Joined: Apr 2023
Posts: 56
Hi Tipmy. Are all the code above produced by ZorroGPT? Those code are quite complex from what I see, with the code separated into different functions, and very organized. But when I use ZorroGPT to come out with a code, the code won't be as "sophisticated" as yours. I am wondering what prompt you use to have it produce such complex code. Thanks!

Last edited by vicknick; 01/02/25 06:39.
Re: PCA and Stochastic Volatility [Re: vicknick] #488509
01/02/25 06:51
01/02/25 06:51
Joined: Sep 2017
Posts: 147
T
TipmyPip Offline OP
Member
TipmyPip  Offline OP
Member
T

Joined: Sep 2017
Posts: 147
First Thank you for looking into the code and being interested in ZorroGPT, The code GPT is producing for Zorro, is still considered simple, procedural code, I guess complex is a very relative term, Thank you for appreciating the complexity and organization.

If you are using ZorroGPT, than you need to define and describe your strategy in a simple English, with no double meanings or lack of precision, In addition, you need to work with short amounts of prompts, not more than 10 focusing on one problem or task, after you finish solving the task, start the prompt from the beginning by copying the code from the previous prompt. Every Strategy has a different description, so will the prompt or the series of prompts.

If you would like to share your strategy example, I will help you to formulize prompt

Last edited by TipmyPip; 01/02/25 06:52.
Page 5 of 9 1 2 3 4 5 6 7 8 9

Moderated by  Petra 

Powered by UBB.threads™ PHP Forum Software 7.7.1