Wednesday, April 15, 2026
Kinstra Trade
  • Home
  • Bitcoin
  • Altcoin
    • Altcoin
    • Ethereum
    • Crypto Exchanges
  • Trading
  • Blockchain
  • NFT
  • Metaverse
  • DeFi
  • Web3
  • Scam Alert
  • Analysis
Crypto Marketcap
  • Home
  • Bitcoin
  • Altcoin
    • Altcoin
    • Ethereum
    • Crypto Exchanges
  • Trading
  • Blockchain
  • NFT
  • Metaverse
  • DeFi
  • Web3
  • Scam Alert
  • Analysis
No Result
View All Result
Kinstra Trade
No Result
View All Result
Home Trading News Forex

How to setup Grid Copier with Google Apps Script (step-by-step) – Other – 18 February 2026

February 18, 2026
in Forex
Reading Time: 8 mins read
A A
0
How to setup Grid Copier with Google Apps Script (step-by-step) – Other – 18 February 2026
Share on FacebookShare on Twitter


Why do we want Google Apps Script?

To trade commerce knowledge between separate MetaTrader terminals, a easy relay server is required. Google Apps Script acts as a free middleman that transfers commerce occasions from the Grasp account to the Slave account. It ensures dependable supply of occasions even after web interruptions or terminal restarts and doesn’t require a VPS or devoted server.

Find out how to create and deploy Google Apps Script

Go to https://script.google.com and Click on Begin scripting

Click on New challenge

Delete the default code and paste the script offered under the instruction steps

Press Ctrl + S to save lots of the challenge (the highest menu will grow to be lively)

Click on Deploy within the top-right nook and choose New deployment

Within the opened window, click on Choose sort (⚙️) and select Net app

In the Description subject, enter Model 1 (any textual content is okay). Set Who has entry to Anybody and depart Execute as unchanged

Click on Deploy – your Apps Script URL shall be generated. Copy and paste this URL into the EA enter settings

const API_KEY   = ‘I_AM_API_KEY’;


const MAX_PRUNE = 200;


const CONSUMER_TTL_MS = 6 * 60 * 60 * 1000;


const MAX_CONSUMERS_PER_CHANNEL = 50;



operate doPost(e) {
  const lock = LockService.getScriptLock();
  let locked = false;

  attempt {
    lock.waitLock(10000);
    locked = true;

    if (!e || !e.postData || !e.parameter) return _resp({ okay:false, error:‘no knowledge’ });

    const key = (e.parameter.key || ”).toString();
    if (key !== API_KEY) return _resp({ okay:false, error:‘forbidden’ });

    const channel  = (e.parameter.channel || ‘default’).toString();
    const client = (e.parameter.client || ”).toString();
    const c        = client || ‘single’;

    const retailer = PropertiesService.getScriptProperties();

    
    let uncooked = e.postData.contents || ‘{}’;
    uncooked = uncooked.substitute(/[u0000-u001F]+$/g, ”);

    let physique;
    attempt {
      physique = JSON.parse(uncooked);
    } catch (parseErr) {
      return _resp({ okay:false, error:‘dangerous json’, particulars:String(parseErr) });
    }

    
    
    _touchConsumerFast(retailer, channel, c);

    
    if (physique && physique.motion === ‘ack’) {
      const lastId = Quantity(physique.last_id || 0);
      if (!lastId) return _resp({ okay:false, error:‘dangerous ack’ });

      retailer.setProperty(_ackKey(channel, c), String(lastId));

      
      _pruneByMinAckFast(retailer, channel);

      return _resp({ okay:true, ack:lastId });
    }

    
    const nextId = _nextSeq(retailer, channel);

    physique.id = nextId;
    physique.server_time_ms = Date.now();

    
    retailer.setProperty(_evKey(channel, nextId), JSON.stringify(physique));

    
    const minKey = _minKey(channel);
    const curMin = Quantity(retailer.getProperty(minKey) || ‘0’);
    if (!curMin) retailer.setProperty(minKey, String(nextId));

    return _resp({ okay:true, last_id: nextId });

  } catch (err) {
    return _resp({
      okay:false,
      error:‘exception’,
      message:String(err),
      stack:(err && err.stack) ? String(err.stack) : ”
    });
  } lastly {
    if (locked) {
      attempt { lock.releaseLock(); } catch(_) {}
    }
  }
}

operate doGet(e) {
  const lock = LockService.getScriptLock();
  let locked = false;

  attempt {
    lock.waitLock(10000);
    locked = true;

    if (!e || !e.parameter) return _resp({ okay:false, error:‘no params’ });

    const key = (e.parameter.key || ”).toString();
    if (key !== API_KEY) return _resp({ okay:false, error:‘forbidden’ });

    const channel  = (e.parameter.channel || ‘default’).toString();
    const client = (e.parameter.client || ”).toString();
    const c        = client || ‘single’;
    const restrict    = Math.max(1, Math.min(100, Quantity(e.parameter.restrict || 20)));

    const retailer = PropertiesService.getScriptProperties();

    
    
    _touchConsumerFast(retailer, channel, c);

    const minId = Quantity(retailer.getProperty(_minKey(channel)) || ‘0’);
    const seq   = Quantity(retailer.getProperty(_seqKey(channel)) || ‘0’);

    const ackKey = _ackKey(channel, c);
    let ack = Quantity(retailer.getProperty(ackKey) || ‘0’);

    
    if (minId > 0) {
      const floorAck = Math.max(0, minId – 1);
      if (ack < floorAck) {
        ack = floorAck;
        retailer.setProperty(ackKey, String(ack));
      }
    }

    
    const mode = (e.parameter.mode || ”).toString();
    if (mode === ‘well being’ || mode === ‘debug’) {
      const shoppers = _listActiveConsumersFast(retailer, channel);
      const minAck = _minAckFast(retailer, channel, shoppers);
      const out = { okay:true, channel, client:c, ack, seq, min_id:minId, active_consumers:shoppers, min_ack:minAck };

      if (mode === ‘debug’) {
        
        const seen = {};
        for (const cc of shoppers) ‘0’);
        
        out.seen = seen;
      }
      return _resp(out);
    }

    const occasions = [];
    let missing_id = 0;

    
    for (let id = ack + 1; id <= seq && occasions.size < restrict; id++) {
      const evStr = retailer.getProperty(_evKey(channel, id));

      if (!evStr) {
        missing_id = id;
        break;
      }

      attempt {
        occasions.push(JSON.parse(evStr));
      } catch (parseErr) {
        missing_id = id;
        break;
      }
    }

    
    if (missing_id && minId > 0 && missing_id < minId) {
      const newAck = Math.max(0, minId – 1);
      retailer.setProperty(ackKey, String(newAck));

      const events2 = [];
      let missing2 = 0;

      for (let id = newAck + 1; id <= seq && events2.size < restrict; id++) {
        const evStr = retailer.getProperty(_evKey(channel, id));
        if (!evStr) { missing2 = id; break; }
        attempt { events2.push(JSON.parse(evStr)); } catch (_) { missing2 = id; break; }
      }

      if (!missing2) {
        return _resp({ okay:true, ack: newAck, seq: seq, occasions: events2 });
      }

      
      return _resp({
        okay:false,
        error:‘gap_detected’,
        ack: newAck,
        seq: seq,
        missing_id: missing2
      });
    }

    if (missing_id) {
      return _resp({
        okay:false,
        error:‘gap_detected’,
        ack: ack,
        seq: seq,
        missing_id: missing_id
      });
    }

    return _resp({ okay:true, ack: ack, seq: seq, occasions: occasions });

  } catch (err) {
    return _resp({
      okay:false,
      error:‘exception’,
      message:String(err),
      stack:(err && err.stack) ? String(err.stack) : ”
    });
  } lastly {
    if (locked) {
      attempt { lock.releaseLock(); } catch(_) {}
    }
  }
}



operate _nextSeq(retailer, channel) ‘0’) + 1;
  retailer.setProperty(ok, String(subsequent));
  return subsequent;






operate _touchConsumerFast(retailer, channel, client) {
  const now = Date.now();
  retailer.setProperty(_seenKey(channel, client), String(now));

  const listKey = _consumersKey(channel);
  let arr = [];
  attempt catch(_) { arr = []; }

  if (arr.indexOf(client) < 0) {
    arr.push(client);
    
    if (arr.size > MAX_CONSUMERS_PER_CHANNEL) arr = arr.slice(arr.size – MAX_CONSUMERS_PER_CHANNEL);
    retailer.setProperty(listKey, JSON.stringify(arr));
  }

  const ackKey = _ackKey(channel, client);
  const ackStr = retailer.getProperty(ackKey);

  
  
  if (ackStr === null || ackStr === undefined || ackStr === ”)

  
  const minId = Quantity(retailer.getProperty(_minKey(channel)) || ‘0’);
  const ack = Quantity(ackStr || ‘0’);
  if (minId > 0) {
    const floorAck = Math.max(0, minId – 1);
    if (ack < floorAck) retailer.setProperty(ackKey, String(floorAck));
  }
}

operate _listActiveConsumersFast(retailer, channel) {
  const now = Date.now();
  const listKey = _consumersKey(channel);

  let arr = [];
  attempt catch(_) { arr = []; }

  const lively = [];
  for (const c of arr)

  if (lively.size === 0) lively.push(‘single’);
  return lively;
}

operate _minAckFast(retailer, channel, shoppers) {
  let min = null;
  for (const c of shoppers)
  return min === null ? 0 : min;
}

operate _pruneByMinAckFast(retailer, channel) {
  const shoppers = _listActiveConsumersFast(retailer, channel);
  const minAck = _minAckFast(retailer, channel, shoppers);
  if (minAck <= 0) return;

  _pruneAckedUpTo(retailer, channel, minAck);
}

operate _pruneAckedUpTo(retailer, channel, ackId) {
  const minKey = _minKey(channel);
  let minId = Quantity(retailer.getProperty(minKey) || ‘0’);
  if (!minId) return;

  let eliminated = 0;
  whereas (minId && minId <= ackId && eliminated < MAX_PRUNE) {
    retailer.deleteProperty(_evKey(channel, minId));
    minId++;
    eliminated++;
  }

  const seq = Quantity(retailer.getProperty(_seqKey(channel)) || ‘0’);

  if (minId > seq) {
    retailer.deleteProperty(minKey);
  } else {
    retailer.setProperty(minKey, String(minId));
  }
}


operate _seqKey(channel) { return channel + ‘__seq’; }
operate _minKey(channel) { return channel + ‘__min’; }
operate _ackKey(channel, client) { return channel + ‘__ack__’ + client; }
operate _evKey(channel, id) { return channel + ‘__ev__’ + id; }
operate _seenKey(channel, client) { return channel + ‘__seen__’ + client; }
operate _consumersKey(channel) { return channel + ‘__consumers’; }

operate _resp(obj) {
  
  
  
  return ContentService
    .createTextOutput(JSON.stringify(obj))
    .setMimeType(ContentService.MimeType.JSON);
}



Source link

Tags: AppsCopierFebruaryGoogleGridScriptSetupStepbyStep
Previous Post

Dogecoin price tests $0.1 as this chart pattern hints at possible rebound

Next Post

XRP gains momentum as Arizona moves to add it to state crypto reserve

Related Posts

Ethereum analysis today with tradeCompass
Forex

Ethereum analysis today with tradeCompass

tradeCompass Abstract Map for right this moment's ETH futures day merchantsBullish threshold: $2425Bearish threshold: $2230ETH has clearly improved from the...

by Kinstra Trade
April 15, 2026
Tick Volume Indicator MT5 – ForexMT4Indicators.com
Forex

Tick Volume Indicator MT5 – ForexMT4Indicators.com

The tick quantity indicator counts value updates throughout a selected timeframe. Every time a forex pair’s value modifications—whether or not...

by Kinstra Trade
April 15, 2026
Growth resilience faces external risks – DBS
Forex

Growth resilience faces external risks – DBS

DBS economist Chua Han Teng highlights that Singapore’s 1Q26 GDP development was resilient, with actual GDP up 4.6% year-on-year, however...

by Kinstra Trade
April 15, 2026
How the result is formed in Owl Smart Levels: in practice and examples – Statistics – 14 April 2026
Forex

How the result is formed in Owl Smart Levels: in practice and examples – Statistics – 14 April 2026

Most individuals are searching for the reply to 1 query: how a lot are you able to earn. However in...

by Kinstra Trade
April 14, 2026
investingLive Asia-Pacific FX news wrap: US-Iran talks again may be as soon as Thursday
Forex

investingLive Asia-Pacific FX news wrap: US-Iran talks again may be as soon as Thursday

Abstract:Diplomacy hopes carry sentiment; oil eases on Iran discuss optimism US-Iran talks ongoing, with potential new spherical this week Central...

by Kinstra Trade
April 14, 2026
GBP/USD reclaims 1.3500 for the first time since late February
Forex

GBP/USD reclaims 1.3500 for the first time since late February

GBP/USD opened the brand new week on the mushy facet, dipping to a session low close to 1.3380, however staged...

by Kinstra Trade
April 14, 2026
Next Post
XRP gains momentum as Arizona moves to add it to state crypto reserve

XRP gains momentum as Arizona moves to add it to state crypto reserve

Bitcoin Difficulty To Rise 14% Thursday—Why A Massive Jump?

Bitcoin Difficulty To Rise 14% Thursday—Why A Massive Jump?

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Facebook Twitter Instagram Instagram RSS
Kinstra Trade

Stay ahead in the crypto and financial markets with Kinstra Trade. Get real-time news, expert analysis, and updates on Bitcoin, altcoins, blockchain, forex, and global trading trends.

Categories

  • Altcoin
  • Analysis
  • Bitcoin
  • Blockchain
  • Commodities
  • Crypto Exchanges
  • DeFi
  • Ethereum
  • Forex
  • Metaverse
  • NFT
  • Scam Alert
  • Stock Market
  • Web3
No Result
View All Result

Quick Links

  • About Us
  • Advertise With Us
  • Disclaimer
  • Privacy Policy
  • DMCA
  • Cookie Privacy Policy
  • Terms and Conditions
  • Contact Us

Copyright© 2025 Kinstra Trade.
Kinstra Trade is not responsible for the content of external sites.

No Result
View All Result
  • Home
  • Bitcoin
  • Altcoin
    • Altcoin
    • Ethereum
    • Crypto Exchanges
  • Trading
  • Blockchain
  • NFT
  • Metaverse
  • DeFi
  • Web3
  • Scam Alert
  • Analysis

Copyright© 2025 Kinstra Trade.
Kinstra Trade is not responsible for the content of external sites.