• Latest
  • Trending
  • All
  • Market Updates
  • Cryptocurrency
  • Blockchain
  • Investing
  • Commodities
  • Personal Finance
  • Technology
  • Business
  • Real Estate
  • Finance
Soft Manager – Trading Ideas – 5 August 2025

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

February 18, 2026
Stocks making the biggest moves after hours: AKAM, OPEN, LYV

Stocks making the biggest moves after hours: AKAM, OPEN, LYV

February 20, 2026
Bitcoin $60K Retest Odds Rise As Bearish Options, ETF Outflows Show Fear

Bitcoin $60K Retest Odds Rise As Bearish Options, ETF Outflows Show Fear

February 20, 2026
OpenAI deepens India push with Pine Labs fintech partnership

OpenAI deepens India push with Pine Labs fintech partnership

February 20, 2026
Soft Manager – Trading Ideas – 5 August 2025

RSI Indicator: Advantages, Disadvantages and Modern Alternative – Analytics & Forecasts – 20 February 2026

February 20, 2026
Japan flash PMIs rise in February; composite hits 53.8, exports surge

Japan flash PMIs rise in February; composite hits 53.8, exports surge

February 20, 2026
Four Sub-$60,000 BTC Price Levels Form Bitcoin Bottom ‘Roadmap’

Four Sub-$60,000 BTC Price Levels Form Bitcoin Bottom ‘Roadmap’

February 19, 2026
Inside the Gay Tech Mafia

Inside the Gay Tech Mafia

February 19, 2026
This new Windows 11 taskbar tool lets you test your internet speed in seconds – how to try it

This new Windows 11 taskbar tool lets you test your internet speed in seconds – how to try it

February 19, 2026
Canadian consumer still spending — Canadian Tire Q4 confirms resilience

Canadian consumer still spending — Canadian Tire Q4 confirms resilience

February 19, 2026
Nasdaq Today (Now) | investingLive

Nasdaq Today (Now) | investingLive

February 19, 2026
Did Quantum Computing Fears Crash Bitcoin? NYDIG Says No

Did Quantum Computing Fears Crash Bitcoin? NYDIG Says No

February 19, 2026
Stocks making the biggest moves premarket: WMT, HIMS, CVNA, FIG

Stocks making the biggest moves premarket: WMT, HIMS, CVNA, FIG

February 19, 2026
Friday, February 20, 2026
No Result
View All Result
InvestorNewsToday.com
  • Home
  • Market
  • Business
  • Finance
  • Investing
  • Real Estate
  • Commodities
  • Crypto
  • Blockchain
  • Personal Finance
  • Tech
InvestorNewsToday.com
No Result
View All Result
Home Investing

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

by Investor News Today
February 18, 2026
in Investing
0
Soft Manager – Trading Ideas – 5 August 2025
492
SHARES
1.4k
VIEWS
Share on FacebookShare on Twitter


Why do we want Google Apps Script?

To alternate commerce information 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.

Tips on how to create and deploy Google Apps Script

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

  2. Click on New challenge


  3. Delete the default code and paste the script supplied under the instruction steps


  4. Press Ctrl + S to save lots of the challenge (the highest menu will change into lively)


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

  6. Within the opened window, click on Choose kind (⚙️) and select Internet app


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


  8. Click on Deploy – your Apps Script URL will probably 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 information' });

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

    const channel  = (e.parameter.channel || 'default').toString();
    const shopper = (e.parameter.shopper || '').toString();
    const c        = shopper || 'single';

    const retailer = PropertiesService.getScriptProperties();

    
    let uncooked = e.postData.contents || '{}';
    uncooked = uncooked.change(/[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 shopper = (e.parameter.shopper || '').toString();
    const c        = shopper || '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 customers = _listActiveConsumersFast(retailer, channel);
      const minAck = _minAckFast(retailer, channel, customers);
      const out = { okay:true, channel, shopper:c, ack, seq, min_id:minId, active_consumers:customers, min_ack:minAck };

      if (mode === 'debug') {
        
        const seen = {};
        for (const cc of customers)  '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) 





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

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

  if (arr.indexOf(shopper) < 0) {
    arr.push(shopper);
    
    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, shopper);
  const ackStr = retailer.getProperty(ackKey);

  
  
  if (ackStr === null || ackStr === undefined || ackStr === '')  '0');
    retailer.setProperty(ackKey, String(Math.max(0, seq)));
    return;
  

  
  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)  '0');
    if (!seen) proceed;
    if (now - seen <= CONSUMER_TTL_MS) lively.push(c);
  

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

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

operate _pruneByMinAckFast(retailer, channel) {
  const customers = _listActiveConsumersFast(retailer, channel);
  const minAck = _minAckFast(retailer, channel, customers);
  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, shopper) { return channel + '__ack__' + shopper; }
operate _evKey(channel, id) { return channel + '__ev__' + id; }
operate _seenKey(channel, shopper) { return channel + '__seen__' + shopper; }
operate _consumersKey(channel) { return channel + '__consumers'; }

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



Source link

Tags: appsCOPIERFebruaryGooglegridScriptSetupStepByStep
Share197Tweet123
Previous Post

Two-thirds of Japanese firms concerned about Takaichi fiscal discipline

Next Post

Google’s AI music maker is coming to the Gemini app

Investor News Today

Investor News Today

Next Post
Google’s AI music maker is coming to the Gemini app

Google’s AI music maker is coming to the Gemini app

  • Trending
  • Comments
  • Latest
Want a Fortell Hearing Aid? Well, Who Do You Know?

Want a Fortell Hearing Aid? Well, Who Do You Know?

December 3, 2025
Private equity groups prepare to offload Ensemble Health for up to $12bn

Private equity groups prepare to offload Ensemble Health for up to $12bn

May 16, 2025
Lars Windhorst’s Tennor Holding declared bankrupt

Lars Windhorst’s Tennor Holding declared bankrupt

June 18, 2025
The human harbor: Navigating identity and meaning in the AI age

The human harbor: Navigating identity and meaning in the AI age

July 14, 2025
Why America’s economy is soaring ahead of its rivals

Why America’s economy is soaring ahead of its rivals

0
Dollar climbs after Donald Trump’s Brics tariff threat and French political woes

Dollar climbs after Donald Trump’s Brics tariff threat and French political woes

0
Nato chief Mark Rutte’s warning to Trump

Nato chief Mark Rutte’s warning to Trump

0
Top Federal Reserve official warns progress on taming US inflation ‘may be stalling’

Top Federal Reserve official warns progress on taming US inflation ‘may be stalling’

0
Stocks making the biggest moves after hours: AKAM, OPEN, LYV

Stocks making the biggest moves after hours: AKAM, OPEN, LYV

February 20, 2026
Bitcoin $60K Retest Odds Rise As Bearish Options, ETF Outflows Show Fear

Bitcoin $60K Retest Odds Rise As Bearish Options, ETF Outflows Show Fear

February 20, 2026
OpenAI deepens India push with Pine Labs fintech partnership

OpenAI deepens India push with Pine Labs fintech partnership

February 20, 2026
Soft Manager – Trading Ideas – 5 August 2025

RSI Indicator: Advantages, Disadvantages and Modern Alternative – Analytics & Forecasts – 20 February 2026

February 20, 2026

Live Prices

© 2024 Investor News Today

No Result
View All Result
  • Home
  • Market
  • Business
  • Finance
  • Investing
  • Real Estate
  • Commodities
  • Crypto
  • Blockchain
  • Personal Finance
  • Tech

© 2024 Investor News Today