Guides

Keep connection live

Follow these steps to maintain a live WebSocket connection with the Deriv API:

Import the Deriv API library

Import the DerivAPIBasic library, which provides an interface to interact with the Deriv WebSocket API:

import DerivAPIBasic from 'https://cdn.skypack.dev/@deriv/deriv-api/dist/DerivAPIBasic';

Establish a WebSocket connection

Create a WebSocket connection using your app_id and the API URL:

(wss://ws.derivws.com/websockets/v3?app_id=${app_id}).

This connection will be used to send and receive messages from the Deriv API.

const connection = new WebSocket(wss://ws.derivws.com/websockets/v3?app_id=${app_id});

Create an API object

Create an instance of DerivAPIBasic, passing the WebSocket connection as a parameter.

This object interacts with the API, such as subscribing to proposals and sending pings.

const api = new DerivAPIBasic({ connection });

Send a proposal subscription

The proposal() function subscribes to a proposal and sends details such as the trade amount, currency, contract type, duration, and asset symbol.

After this subscription, the API will send real-time updates about the proposal (market data).

const proposal = () => {  
  api.subscribe({  
    proposal: 1,  
    subscribe: 1,  
    amount: 10,  
    basis: 'payout',  
    contract_type: 'CALL',  
    currency: 'USD',  
    duration: 1,  
    duration_unit: 'm',  
    symbol: 'R_100',  
    barrier: '+0.1',  
  });  
};

Send ping to keep the connection alive

The ping() function sends a "ping" message every 30 seconds using setInterval.

This ensures that the WebSocket connection remains active, as WebSocket servers may close idle connections.

const ping = () => {
  setInterval(() => {
    api.ping();
  }, 30000);
};

Handle WebSocket responses

The wsResponse() function processes incoming WebSocket messages and handles:

  • Errors: Logs errors and disconnects the WebSocket if an error is received.
  • Proposal Messages: Logs proposal details (e.g., ask price, payout).
  • Ping Messages: Logs ping responses from the server.
const wsResponse = async (res) => {
  const data = JSON.parse(res.data);
  if (data.error !== undefined) {
    console.log('Error: %s ', data.error.message);
    connection.removeEventListener('message', wsResponse, false);
    await api.disconnect();
  } else if (data.msg_type === 'proposal') {
    console.log('Details: %s', data.proposal.longcode);
    console.log('Ask Price: %s', data.proposal.display_value);
    console.log('Payout: %f', data.proposal.payout);
    console.log('Spot: %f', data.proposal.spot);
  } else if (data.msg_type === 'ping') {
    console.log('ping');
  }
};

Start the signal processing

The checkSignal() function starts the signal processing by:

  1. proposal(): Subscribes to market data.
  2. ping(): Starts sending pings.
  3. connection.addEventListener('message', wsResponse): Listens for messages from the WebSocket server and processing them using wsResponse().
const checkSignal = () => {
  proposal();
  ping();
  connection.addEventListener('message', wsResponse);
};

End the WebSocket subscription

The endCall() function stops receiving proposal updates by:

  1. Removing the WebSocket message listener.
  2. Calling unsubscribe() on the proposal()to stop the subscription.
const endCall = () => {
  connection.removeEventListener('message', wsResponse, false);
  proposal().unsubscribe();
};

These steps outline how the code works to establish a WebSocket connection, subscribe to proposals, keep the connection alive with pings, handle responses, and eventually unsubscribe from the proposals.

import DerivAPIBasic from '@deriv/deriv-api/dist/DerivAPIBasic.js';

const app_id = 1089; // Replace with your app_id if different.
const connection = new WebSocket(`wss://ws.derivws.com/websockets/v3?app_id=${app_id}`);
const api = new DerivAPIBasic({ connection });

const proposal = () => {
  api.subscribe({
    proposal: 1,
    subscribe: 1,
    amount: 10,
    basis: 'payout',
    contract_type: 'CALL',
    currency: 'USD',
    duration: 1,
    duration_unit: 'm',
    symbol: 'R_100',
    barrier: '+0.1',
  });
};

const ping = () => {
  setInterval(() => {
    api.ping();
  }, 30000); // Sends a ping message every 30 seconds
};

const wsResponse = async (res) => {
  const data = JSON.parse(res.data);
  if (data.error !== undefined) {
    console.log('Error:', data.error.message);
    connection.removeEventListener('message', wsResponse);
    await api.disconnect();
  } else if (data.msg_type === 'proposal') {
    console.log('Details:', data.proposal.longcode);
    console.log('Ask Price:', data.proposal.display_value);
    console.log('Payout:', data.proposal.payout);
    console.log('Spot:', data.proposal.spot);
  } else if (data.msg_type === 'ping') {
    console.log('ping');
  }
};

const checkSignal = () => {
  proposal();
  ping();
  connection.addEventListener('message', wsResponse);
};

// Browser-specific functionality
if (typeof document !== 'undefined') {
  const keep_alive_button = document.querySelector('#keep_alive');
  const end_call_button = document.querySelector('#end_call');

  keep_alive_button.addEventListener('click', checkSignal);
  end_call_button.addEventListener('click', () => {
    connection.removeEventListener('message', wsResponse);
    proposal().unsubscribe();
  });
} else {
  // For Node.js environment: start the signal check immediately
  checkSignal();
}

/*
Instructions:

1. **Install Node.js**: Ensure you have Node.js installed from https://nodejs.org/.
2. **Install Deriv API Package**: Use npm to install the Deriv API package by running:
npm install @deriv/deriv-api
3. **Save the Code**: Save the code in a file, e.g., `websocket_example.js`.
4. **Run in Node.js**:
- In your terminal, navigate to the directory where you saved the file.
- Run the script using:
  ```
  node websocket_example.js
  ```
5. **Run in a Browser**:
- Include the script in your HTML page, and ensure there are two buttons with IDs `keep_alive` and `end_call`.
- Use the `keep_alive` button to start the signal check and the `end_call` button to unsubscribe from the proposal and stop receiving messages.

Replace the `app_id` in the URL if you have a different app ID.
*/
import Foundation

// Make webSocketTask a global variable to keep the connection open
var webSocketTask: URLSessionWebSocketTask?

// Function to create and handle WebSocket connection
func connectWebSocket() {
    let appID = 1089 // Replace with your app_id.
    let url = URL(string: "wss://ws.derivws.com/websockets/v3?app_id=\(appID)")! // WebSocket URL with the app_id
    let request = URLRequest(url: url)
    
    // Initialize webSocketTask with URLSession
    webSocketTask = URLSession.shared.webSocketTask(with: request)
    
    // Start the WebSocket connection
    webSocketTask?.resume()
    print("[open] Connection established")
    
    // Function to send a proposal subscription request
    func sendProposalSubscription() {
        let proposalRequest = [
            "proposal": 1,
            "subscribe": 1,
            "amount": 10,
            "basis": "payout",
            "contract_type": "CALL",
            "currency": "USD",
            "duration": 1,
            "duration_unit": "m",
            "symbol": "R_100",
            "barrier": "+0.1"
        ] as [String: Any]
        
        if let proposalData = try? JSONSerialization.data(withJSONObject: proposalRequest, options: []) {
            let message = URLSessionWebSocketTask.Message.data(proposalData)
            webSocketTask?.send(message) { error in
                if let error = error {
                    print("[error] Failed to send proposal subscription: \(error.localizedDescription)")
                } else {
                    print("Proposal subscription sent.")
                }
            }
        }
    }
    
    // Function to send a ping message every 30 seconds
    func startPing() {
        Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { _ in
            let pingMessage = URLSessionWebSocketTask.Message.string("{\"ping\": 1}")
            webSocketTask?.send(pingMessage) { error in
                if let error = error {
                    print("[error] Failed to send ping: \(error.localizedDescription)")
                } else {
                    print("Ping sent to keep connection alive.")
                }
            }
        }
    }
    
    // Function to receive messages from the server
    func receiveMessage() {
        webSocketTask?.receive { result in
            switch result {
            case .success(let message):
                switch message {
                case .string(let text):
                    if let data = text.data(using: .utf8),
                       let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                        handleServerMessage(json)
                    }
                case .data(let data):
                    print("[message] Binary data received: \(data)")
                @unknown default:
                    print("[message] Received unknown message type")
                }
                
                // Continue to receive messages
                receiveMessage()
                
            case .failure(let error):
                print("[error] Failed to receive message: \(error.localizedDescription)")
            }
        }
    }
    
    // Function to handle the proposal and ping response from server
    func handleServerMessage(_ data: [String: Any]) {
        if let error = data["error"] as? [String: Any], let message = error["message"] as? String {
            print("[Error] \(message)")
        } else if data["msg_type"] as? String == "proposal", let proposal = data["proposal"] as? [String: Any] {
            print("Details: \(proposal["longcode"] ?? "")")
            print("Ask Price: \(proposal["display_value"] ?? "")")
            print("Payout: \(proposal["payout"] ?? "")")
            print("Spot: \(proposal["spot"] ?? "")")
        } else if data["msg_type"] as? String == "ping" {
            print("[Ping] Ping response received.")
        }
    }
    
    // Start sending the proposal subscription and pinging the server
    sendProposalSubscription()
    startPing()
    receiveMessage()
}

// Function to close the WebSocket connection
func closeWebSocketConnection() {
    webSocketTask?.cancel(with: .normalClosure, reason: nil)
    print("[close] Connection closed cleanly")
}

// Start WebSocket connection
connectWebSocket()

// Keep the program running to wait for messages
RunLoop.main.run()

/*
 * Instructions to Run:
 * 1. Ensure Swift is installed on your machine.
 * 2. Save this code in a file, for example, `WebSocketClient.swift`.
 * 3. Open a terminal, navigate to the directory where you saved the file, and run:
 *      swift WebSocketClient.swift
 * 4. The script connects to the WebSocket server, sends a proposal subscription, and sends a ping every 30 seconds to keep the connection alive.
 */
use tokio_tungstenite::connect_async;
use tokio_tungstenite::tungstenite::protocol::Message;
use futures_util::{SinkExt, StreamExt};
use tokio::{time::interval, sync::Mutex, task::spawn};
use std::sync::Arc;
use serde_json::json;
use url::Url;
use std::time::Duration;

#[tokio::main]
async fn main() {
    let app_id = 1089;
    let url = format!("wss://ws.derivws.com/websockets/v3?app_id={}", app_id);
    let url = Url::parse(&url).expect("Invalid URL");

    // Connect to the WebSocket server and wrap `socket` in Arc<Mutex<_>>
    let (socket, _) = connect_async(url).await.expect("Failed to connect");
    let socket = Arc::new(Mutex::new(socket));

    println!("[open] Connection established");

    // Proposal request JSON
    let proposal_request = json!({
        "proposal": 1,
        "subscribe": 1,
        "amount": 10,
        "basis": "payout",
        "contract_type": "CALL",
        "currency": "USD",
        "duration": 1,
        "duration_unit": "m",
        "symbol": "R_100",
        "barrier": "+0.1"
    });

    // Clone `socket` for the ping task and start pinging every 30 seconds
    let ping_socket = Arc::clone(&socket);
    let ping_task = spawn(async move {
        let mut interval = interval(Duration::from_secs(30));
        loop {
            interval.tick().await;
            let mut socket = ping_socket.lock().await;
            if socket.send(Message::Text(json!({ "ping": 1 }).to_string())).await.is_ok() {
                println!("[ping] Ping sent to keep connection alive.");
            }
        }
    });

    // Clone `socket` for sending the proposal
    let send_socket = Arc::clone(&socket);
    let send_task = spawn(async move {
        let mut socket = send_socket.lock().await;
        if socket.send(Message::Text(proposal_request.to_string())).await.is_ok() {
            println!("Proposal subscription sent.");
        }
    });

    // Task to handle incoming messages
    let receive_socket = Arc::clone(&socket);
    let receive_task = spawn(async move {
        let mut socket = receive_socket.lock().await;
        while let Some(Ok(msg)) = socket.next().await {
            match msg {
                Message::Text(text) => {
                    let data: serde_json::Value = serde_json::from_str(&text).unwrap_or_else(|_| json!({}));
                    if let Some(proposal) = data.get("proposal") {
                        println!("Details: {}", proposal["longcode"]);
                        println!("Ask Price: {}", proposal["display_value"]);
                        println!("Payout: {}", proposal["payout"]);
                        println!("Spot: {}", proposal["spot"]);
                    } else if data.get("msg_type").unwrap_or(&json!("")) == "ping" {
                        println!("[Ping] Ping response received.");
                    } else if let Some(error) = data.get("error") {
                        println!("[Error] {}", error["message"]);
                    }
                }
                _ => {}
            }
        }
    });

    // Await all tasks to complete
    let _ = tokio::try_join!(ping_task, send_task, receive_task);

    // Close the WebSocket connection
    let mut socket = socket.lock().await;
    socket.close(None).await.expect("Failed to close connection");
    println!("[close] Connection closed.");
}

/*
Instructions to run the code:

1. Ensure Rust and Cargo are installed on your machine. You can download them from https://www.rust-lang.org/.
2. Add the necessary dependencies to `Cargo.toml`:

   [dependencies]
   tokio = { version = "1", features = ["full"] }
   tokio-tungstenite = "0.16"
   futures-util = "0.3"
   serde_json = "1.0"
   url = "2.2"

3. Build the project:

   cargo build --release

4. Run the project:

   cargo run --release

Note: Replace `app_id` with your actual app_id if needed.
*/
<?php

require 'vendor/autoload.php';

use WebSocket\Client;

// Replace with your app_id
$app_id = 1089;
$uri = "wss://ws.derivws.com/websockets/v3?app_id=$app_id";

// Create a new WebSocket client
$client = new Client($uri);

try {
    echo "[open] WebSocket connection established.\n";

    // Send a proposal subscription request
    $proposal_request = json_encode([
        "proposal" => 1,
        "subscribe" => 1,
        "amount" => 10,
        "basis" => "payout",
        "contract_type" => "CALL",
        "currency" => "USD",
        "duration" => 1,
        "duration_unit" => "m",
        "symbol" => "R_100",
        "barrier" => "+0.1"
    ]);
    $client->send($proposal_request);
    echo "[sent] Proposal subscription sent.\n";

    // Ping function to keep connection alive
    $ping_interval = 30; // in seconds
    $last_ping_time = time();

    // Main loop to handle responses and send ping messages
    while (true) {
        // Check if it's time to send a ping
        if (time() - $last_ping_time >= $ping_interval) {
            $client->send(json_encode(["ping" => 1]));
            echo "[ping] Ping sent to keep connection alive.\n";
            $last_ping_time = time();
        }

        // Receive response from WebSocket
        $response = $client->receive();
        $data = json_decode($response, true);

        if (isset($data["error"])) {
            echo "[error] " . $data["error"]["message"] . "\n";
            break;
        } elseif ($data["msg_type"] === "proposal") {
            $proposal = $data["proposal"];
            echo "[proposal] Details: {$proposal['longcode']}\n";
            echo "[proposal] Ask Price: {$proposal['display_value']}\n";
            echo "[proposal] Payout: {$proposal['payout']}\n";
            echo "[proposal] Spot: {$proposal['spot']}\n";
        } elseif ($data["msg_type"] === "ping") {
            echo "[ping] Ping response received.\n";
        }

        // Sleep briefly to prevent continuous loop
        usleep(500000); // 500ms
    }

    // Close the WebSocket connection
    $client->close();
    echo "[close] WebSocket connection closed.\n";

} catch (Exception $e) {
    echo "[error] " . $e->getMessage() . "\n";
}

/*
Instructions to run the code:

1. Ensure PHP is installed on your machine. You can download it from https://www.php.net/.
2. Install Composer if you haven't already, by downloading it from https://getcomposer.org/.
3. Create a `composer.json` file in the same directory as your PHP script with the following content:

   {
     "require": {
       "textalk/websocket": "^1.5"
     }
   }

4. Run the following command to install the WebSocket library:

   composer install

5. Save the code above to a PHP file, e.g., `websocket_client.php`.
6. Run the code from the command line:

   php websocket_client.php

Note: Replace `app_id` with your actual app_id if needed.
*/
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"nhooyr.io/websocket"
	"nhooyr.io/websocket/wsjson"
)

// Define constants
const (
	webSocketURL = "wss://ws.derivws.com/websockets/v3?app_id=1089"
)

// ProposalRequest defines the structure of the proposal subscription request
type ProposalRequest struct {
	Proposal      int    `json:"proposal"`
	Subscribe     int    `json:"subscribe"`
	Amount        int    `json:"amount"`
	Basis         string `json:"basis"`
	ContractType  string `json:"contract_type"`
	Currency      string `json:"currency"`
	Duration      int    `json:"duration"`
	DurationUnit  string `json:"duration_unit"`
	Symbol        string `json:"symbol"`
	Barrier       string `json:"barrier"`
}

func main() {
	// Set up WebSocket connection context
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// Establish a WebSocket connection
	conn, _, err := websocket.Dial(ctx, webSocketURL, nil)
	if err != nil {
		log.Fatalf("Failed to connect to WebSocket: %v", err)
	}
	defer conn.Close(websocket.StatusNormalClosure, "normal closure")
	fmt.Println("WebSocket connection established.")

	// Send initial proposal subscription request
	err = sendProposalRequest(ctx, conn)
	if err != nil {
		log.Fatalf("Failed to send proposal request: %v", err)
	}

	// Start keep-alive ping
	go keepAlivePing(ctx, conn)

	// Handle incoming messages
	handleResponses(ctx, conn)
}

// sendProposalRequest sends a proposal subscription request to the WebSocket server
func sendProposalRequest(ctx context.Context, conn *websocket.Conn) error {
	// Construct proposal subscription request
	proposal := ProposalRequest{
		Proposal:     1,
		Subscribe:    1,
		Amount:       10,
		Basis:        "payout",
		ContractType: "CALL",
		Currency:     "USD",
		Duration:     1,
		DurationUnit: "m",
		Symbol:       "R_100",
		Barrier:      "+0.1",
	}
	fmt.Println("Sending proposal subscription...")

	return wsjson.Write(ctx, conn, proposal)
}

// keepAlivePing sends a ping message every 30 seconds to keep the connection alive
func keepAlivePing(ctx context.Context, conn *websocket.Conn) {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			// Send ping message
			pingMsg := map[string]int{"ping": 1}
			err := wsjson.Write(ctx, conn, pingMsg)
			if err != nil {
				log.Printf("Ping failed: %v", err)
				return
			}
			fmt.Println("Ping sent.")
		case <-ctx.Done():
			return
		}
	}
}

// handleResponses listens for and processes messages received from the WebSocket server
func handleResponses(ctx context.Context, conn *websocket.Conn) {
	for {
		var response map[string]interface{}
		err := wsjson.Read(ctx, conn, &response)
		if err != nil {
			log.Fatalf("Error reading message: %v", err)
		}

		// Process response messages
		msgType := response["msg_type"]
		switch msgType {
		case "proposal":
			// Print proposal details
			proposal := response["proposal"].(map[string]interface{})
			fmt.Printf("Details: %v\n", proposal["longcode"])
			fmt.Printf("Ask Price: %v\n", proposal["display_value"])
			fmt.Printf("Payout: %v\n", proposal["payout"])
			fmt.Printf("Spot: %v\n", proposal["spot"])
		case "ping":
			fmt.Println("[Ping] Ping response received.")
		default:
			fmt.Printf("Received message: %v\n", response)
		}
	}
}

/*
Instructions to run the code locally:

1. Install Go: Ensure you have Go installed on your machine. You can download it from https://golang.org/dl/.

2. Save the code:
   - Save this code into a file named `connect.go`.

3. Initialize a Go module:
   - Open a terminal in the directory containing `connect.go`.
   - Run `go mod init app` to initialize a new Go module.
   - Run `go get nhooyr.io/websocket` to install the WebSocket package dependency.

4. Run the code:
   - Execute the code using the command `go run connect.go`.
   - Alternatively, you can build and run the executable:
     ```
     go build -o connect connect.go
     ./connect
     ```
5. Replace `app_id=1089` with your actual app_id if needed.
*/
using System;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

class WebSocketExample
{
    private static readonly Uri uri = new Uri("wss://ws.derivws.com/websockets/v3?app_id=1089"); // Replace with your app_id if needed
    private static readonly int pingInterval = 30000; // Ping every 30 seconds

    public static async Task Main(string[] args)
    {
        using (ClientWebSocket webSocket = new ClientWebSocket())
        {
            Console.WriteLine("Attempting to connect to WebSocket...");

            await webSocket.ConnectAsync(uri, CancellationToken.None);
            Console.WriteLine("WebSocket connection established.");

            // Send initial proposal subscription request
            await SendProposalSubscription(webSocket);

            // Start a task to send pings to keep connection alive
            Task keepAlivePingTask = KeepAlivePing(webSocket);

            // Handle responses from the server
            await HandleResponses(webSocket);

            // Ensure the keep-alive ping task finishes
            await keepAlivePingTask;
        }
    }

    private static async Task SendProposalSubscription(ClientWebSocket webSocket)
    {
        var proposalRequest = new
        {
            proposal = 1,
            subscribe = 1,
            amount = 10,
            basis = "payout",
            contract_type = "CALL",
            currency = "USD",
            duration = 1,
            duration_unit = "m",
            symbol = "R_100",
            barrier = "+0.1"
        };

        string requestJson = JsonSerializer.Serialize(proposalRequest);
        var bytes = Encoding.UTF8.GetBytes(requestJson);
        await webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, CancellationToken.None);
        Console.WriteLine("Proposal subscription sent.");
    }

    private static async Task KeepAlivePing(ClientWebSocket webSocket)
    {
        while (webSocket.State == WebSocketState.Open)
        {
            await Task.Delay(pingInterval);

            var pingRequest = new { ping = 1 };
            string pingJson = JsonSerializer.Serialize(pingRequest);
            var pingBytes = Encoding.UTF8.GetBytes(pingJson);
            await webSocket.SendAsync(new ArraySegment<byte>(pingBytes), WebSocketMessageType.Text, true, CancellationToken.None);
            Console.WriteLine("Ping sent to keep connection alive.");
        }
    }

private static async Task HandleResponses(ClientWebSocket webSocket)
{
    var buffer = new byte[1024 * 4];

    while (webSocket.State == WebSocketState.Open)
    {
        var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

        if (result.MessageType == WebSocketMessageType.Close)
        {
            Console.WriteLine("WebSocket connection closed by server.");
            await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
        }
        else
        {
            string response = Encoding.UTF8.GetString(buffer, 0, result.Count);
            var data = JsonSerializer.Deserialize<JsonElement>(response);

            if (data.TryGetProperty("error", out var error))
            {
                Console.WriteLine($"[Error] {error.GetProperty("message").GetString()}");
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing due to error", CancellationToken.None);
                break;
            }

            if (data.TryGetProperty("msg_type", out var msgType))
            {
                if (msgType.GetString() == "proposal")
                {
                    var proposal = data.GetProperty("proposal");

                    // Extract proposal details with type-checking
                    string longcode = proposal.GetProperty("longcode").GetString();
                    Console.WriteLine($"Details: {longcode}");

                    string displayValue = proposal.GetProperty("display_value").GetRawText();
                    Console.WriteLine($"Ask Price: {displayValue}");

                    string payout = proposal.GetProperty("payout").GetRawText();
                    Console.WriteLine($"Payout: {payout}");

                    string spot = proposal.GetProperty("spot").GetRawText();
                    Console.WriteLine($"Spot: {spot}");
                }
                else if (msgType.GetString() == "ping")
                {
                    Console.WriteLine("[Ping] Ping response received.");
                }
            }
        }
    }
}
}

/*
Instructions to run the code locally:

1. Ensure you have .NET SDK installed. You can download it from https://dotnet.microsoft.com/download.

2. Save the code to a file named `WebSocketExample.cs`.

3. Open a terminal in the directory containing `WebSocketExample.cs`.

4. If using the .NET CLI, you can run the code with:
   - `dotnet new console -o WebSocketExample` (if creating a new project)
   - Move `WebSocketExample.cs` into the project directory `WebSocketExample`.
   - Navigate to the project directory: `cd WebSocketExample`.
   - Run `dotnet add package System.Net.WebSockets.Client` to add the WebSocket client dependency.
   - Run the code: `dotnet run`.

5. Alternatively, you can use an IDE like Visual Studio to create a console application, add the `System.Net.WebSockets.Client` package, and then run the application.

6. Replace `app_id=1089` in the URL with your actual app_id if needed.
*/
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#include <time.h>

// Set up WebSocket context and connection details
static struct lws_context *context;
static int interrupted = 0, port = 443, ssl_connection = LCCSCF_USE_SSL;
static const char *server_address = "ws.derivws.com";
static const char *path = "/websockets/v3?app_id=1089";
static const char *pro = "lws-minimal-client";

// Interval for the ping in seconds
static const int ping_interval = 30;
static time_t last_ping_time = 0;

// Signal handler for graceful shutdown
static void sigint_handler(int sig) {
    interrupted = 1;
}

// Function to send a ping message
void send_ping(struct lws *wsi) {
    const char *ping_msg = "{\"ping\": 1}";
    unsigned char buf[LWS_PRE + 20];
    memcpy(&buf[LWS_PRE], ping_msg, strlen(ping_msg));
    lws_write(wsi, &buf[LWS_PRE], strlen(ping_msg), LWS_WRITE_TEXT);
    lwsl_user("Ping sent\n");
}

// Function to send a proposal subscription message
void send_proposal(struct lws *wsi) {
    const char *proposal_msg = "{\"proposal\": 1, \"subscribe\": 1, \"amount\": 10, \"basis\": \"payout\", \"contract_type\": \"CALL\", \"currency\": \"USD\", \"duration\": 1, \"duration_unit\": \"m\", \"symbol\": \"R_100\", \"barrier\": \"+0.1\"}";
    unsigned char buf[LWS_PRE + 256];
    memcpy(&buf[LWS_PRE], proposal_msg, strlen(proposal_msg));
    lws_write(wsi, &buf[LWS_PRE], strlen(proposal_msg), LWS_WRITE_TEXT);
    lwsl_user("Proposal subscription sent\n");
}

// Callback function for WebSocket events
static int callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                            void *user, void *in, size_t len) {
    switch (reason) {
    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
        lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)");
        interrupted = 1;
        break;

    case LWS_CALLBACK_CLIENT_ESTABLISHED:
        lwsl_user("Connection established\n");
        send_proposal(wsi);  // Send proposal on connection
        lws_callback_on_writable(wsi); // Request writable callback
        break;

    case LWS_CALLBACK_CLIENT_WRITEABLE:
        if (time(NULL) - last_ping_time >= ping_interval) {
            send_ping(wsi);  // Send periodic ping
            last_ping_time = time(NULL);
        }
        break;

    case LWS_CALLBACK_CLIENT_RECEIVE:
        lwsl_hexdump_notice(in, len); // Log received message
        break;

    case LWS_CALLBACK_CLIENT_CLOSED:
        lwsl_user("Connection closed\n");
        interrupted = 1;
        break;

    default:
        break;
    }

    return 0;
}

// Define supported protocols for the WebSocket
static const struct lws_protocols protocols[] = {
    { "lws-minimal-client", callback_minimal, 0, 0, 0, NULL, 0 },
    LWS_PROTOCOL_LIST_TERM
};

// Main function to set up and manage the WebSocket client
int main(int argc, const char **argv) {
    struct lws_context_creation_info info;
    struct lws_client_connect_info i;

    // Handle Ctrl+C interrupt for graceful shutdown
    signal(SIGINT, sigint_handler);
    memset(&info, 0, sizeof info);
    memset(&i, 0, sizeof(i));

    lwsl_user("LWS Deriv ws client\n");

    info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
    info.port = CONTEXT_PORT_NO_LISTEN;
    info.protocols = protocols;
    info.fd_limit_per_thread = 1 + 1 + 1;

    context = lws_create_context(&info);
    if (!context) {
        lwsl_err("lws init failed\n");
        return 1;
    }

    i.context = context;
    i.port = port;
    i.address = server_address;
    i.path = path;
    i.host = i.address;
    i.origin = i.address;
    i.ssl_connection = ssl_connection;
    i.protocol = pro;
    i.local_protocol_name = "lws-minimal-client";

    if (!lws_client_connect_via_info(&i)) {
        lwsl_err("Failed to initiate connection\n");
        return 1;
    }

    // Run the WebSocket client event loop
    while (!interrupted)
        lws_service(context, 0);

    lws_context_destroy(context);
    lwsl_user("Completed\n");

    return 0;
}

/*
 * Instructions:
 * 1. Install the libwebsockets library on your system if it's not already installed.
 *    - On Ubuntu, you can install it by running:
 *        sudo apt-get install libwebsockets-dev
 *    - On macOS, you can use Homebrew:
 *        brew install libwebsockets
 *    - For other operating systems, refer to the libwebsockets documentation for installation details.
 * 2. Compile the code using the following command:
 *      gcc -o connect connect.c -lwebsockets -lssl -lcrypto -lm
 *    - This command links the required libraries: `libwebsockets`, `ssl`, `crypto`, and `m`.
 * 3. Run the compiled executable:
 *      ./connect
 * 4. Ensure you have internet connectivity as the WebSocket will attempt to connect to `ws.derivws.com`.
 * 5. Replace "app_id=1089" in the `path` variable with your actual app_id if required.
 */
import asyncio
from deriv_api import DerivAPI
from deriv_api.subscription_manager import SubscriptionManager

# Replace with your actual app_id
app_id = 1089

async def main():
    # Initialize the DerivAPI instance
    api = DerivAPI(app_id=app_id)

    # Initialize the SubscriptionManager
    subscription_manager = SubscriptionManager(api)

    # Define the proposal request
    proposal_request = {
        "proposal": 1,
        "amount": 10,
        "basis": "payout",
        "contract_type": "CALL",
        "currency": "USD",
        "duration": 1,
        "duration_unit": "m",
        "symbol": "R_100",
        "barrier": "+0.1"
    }

    # Subscribe to the proposal stream
    try:
        proposal_stream = await subscription_manager.subscribe(proposal_request)
        print("Subscribed to proposal stream")

        # Handle incoming messages and print formatted proposal details
        proposal_stream.subscribe(
            on_next=lambda message: print_proposal_details(message),
            on_error=lambda e: print(f"Error: {e}"),
            on_completed=lambda: print("Subscription completed")
        )

        # Function to send a ping every 30 seconds
        async def keep_alive():
            while True:
                await api.ping()  # Send a ping message
                print("Sent ping to keep connection alive")
                await asyncio.sleep(30)  # Ping every 30 seconds

        # Run the keep-alive ping loop and proposal subscription concurrently
        await asyncio.gather(keep_alive())

    except Exception as e:
        print(f"An error occurred: {e}")

    finally:
        # Disconnect from the API
        await api.disconnect()
        print("Disconnected from Deriv API")

# Helper function to format and print proposal details
def print_proposal_details(message):
    data = message.get("proposal", {})
    if data:
        print(f"Details: {data.get('longcode', 'N/A')}")
        print(f"Ask Price: {data.get('display_value', 'N/A')}")
        print(f"Payout: {data.get('payout', 'N/A')}")
        print(f"Spot: {data.get('spot', 'N/A')}")

# Run the main function
if __name__ == "__main__":
    asyncio.run(main())

"""
Instructions to run this code:

1. **Install the Required Library**:
   - Ensure that `python-deriv-api` is installed. If not, install it using:
     ```
     pip install python-deriv-api
     ```
2. **Save and Run the Code**:
   - Save this code to a file, e.g., `connect.py`.
   - Run the script using:
     ```
     python connect.py
     ```
3. **Configuration**:
   - Replace the `app_id` variable with your actual Deriv app ID if needed.

This script will connect to the Deriv API WebSocket, subscribe to a proposal stream, print proposal details, and send a ping every 30 seconds to keep the connection active. 
"""
#!/usr/bin/env perl
use strict;
use warnings;
use v5.014;
use AnyEvent;
use AnyEvent::WebSocket::Client;
use JSON;

# WebSocket URL and app_id
my $app_id = 1089;
my $url = "wss://ws.derivws.com/websockets/v3?app_id=$app_id";

# Create WebSocket client and connection
my $client = AnyEvent::WebSocket::Client->new;
$| = 1;  # Flush output immediately for real-time logging

# Define a ping interval in seconds
my $ping_interval = 30;

# Function to send a proposal subscription request
sub send_proposal {
    my $connection = shift;
    my $proposal_request = encode_json({
        proposal       => 1,
        subscribe      => 1,
        amount         => 10,
        basis          => 'payout',
        contract_type  => 'CALL',
        currency       => 'USD',
        duration       => 1,
        duration_unit  => 'm',
        symbol         => 'R_100',
        barrier        => '+0.1'
    });
    $connection->send($proposal_request);
    say "Proposal subscription sent.";
}

# Establish WebSocket connection
$client->connect($url)->cb(sub {
    my $connection = eval { shift->recv };
    if (!$connection) {
        die "Connection error: $@";
    }
    say "WebSocket connection established.";

    # Set up a repeating timer to send ping every 30 seconds
    my $ping_timer = AnyEvent->timer(
        after    => $ping_interval,
        interval => $ping_interval,
        cb       => sub {
            $connection->send(encode_json({ ping => 1 }));
            say "Ping sent to keep connection alive.";
        }
    );

    # Send the initial proposal subscription
    send_proposal($connection);

    # Handle incoming messages
    $connection->on(each_message => sub {
        my ($connection, $message) = @_;
        my $data = decode_json($message->body);

        # Handle errors
        if ($data->{error}) {
            say "[Error] " . $data->{error}{message};
            $connection->close;
            return;
        }

        # Handle proposal messages
        if ($data->{msg_type} && $data->{msg_type} eq 'proposal') {
            my $proposal = $data->{proposal};
            say "Details: $proposal->{longcode}";
            say "Ask Price: $proposal->{display_value}";
            say "Payout: $proposal->{payout}";
            say "Spot: $proposal->{spot}";
        } elsif ($data->{msg_type} && $data->{msg_type} eq 'ping') {
            say "[Ping] Ping response received.";
        }
    });

    # Handle connection close
    $connection->on(finish => sub {
        say "WebSocket connection closed.";
        $ping_timer = undef;  # Stop the ping timer
    });
});

# Start the AnyEvent event loop
AnyEvent->condvar->recv;

# Instructions to run the code on a local machine:
# 1. Ensure you have Perl installed on your machine.
# 2. Install the necessary Perl modules using the following commands:
#      cpanm AnyEvent AnyEvent::WebSocket::Client JSON
#    If `cpanm` is not installed, install it using `cpan App::cpanminus`.
# 3. Save this script to a file, e.g., `connect.pl`.
# 4. Run the script using the command:
#      perl connect.pl
# This script will connect to the Deriv WebSocket API, subscribe to a proposal, and send a ping every 30 seconds to keep the connection alive.