AutomationFlowsGeneral › Pipsync 01 - Tradingview Paper Signal Validator

Pipsync 01 - Tradingview Paper Signal Validator

PipSync 01 - TradingView Paper Signal Validator. Webhook trigger; 4 nodes.

Webhook trigger★★★★☆ complexity4 nodes
General Trigger: Webhook Nodes: 4 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "PipSync 01 - TradingView Paper Signal Validator",
  "nodes": [
    {
      "parameters": {
        "content": "## Local validation demo only\n\nAccepts a small synthetic TradingView-shaped payload in `paper` or `sandbox` mode. It rejects `live`, performs no network request, stores no replay receipt, and never calls PipSync or a broker.",
        "height": 300,
        "width": 430,
        "color": 7
      },
      "id": "01000000-0000-4000-8000-000000000001",
      "name": "Safety boundary",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -560,
        -240
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "pipsync-demo-paper-signal-validator",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "01000000-0000-4000-8000-000000000002",
      "name": "Synthetic TradingView Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -320,
        80
      ]
    },
    {
      "parameters": {
        "jsCode": "const raw = $json && typeof $json === 'object' && !Array.isArray($json)\n  ? ($json.body ?? $json)\n  : null;\n\nconst errors = [];\nconst allowedKeys = new Set([\n  'schema',\n  'environment',\n  'signal_id',\n  'instrument',\n  'direction',\n  'entry_price',\n  'stop_loss',\n  'take_profit',\n  'created_at',\n]);\n\nif (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n  errors.push({ code: 'INVALID_BODY', field: '$', message: 'Expected one JSON object.' });\n}\n\nconst value = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};\nfor (const key of Object.keys(value)) {\n  if (!allowedKeys.has(key)) {\n    errors.push({ code: 'UNKNOWN_FIELD', field: key, message: 'Field is not part of the demo contract.' });\n  }\n}\n\nif (value.schema !== 'pipsync.tradingview.paper-signal.v1') {\n  errors.push({ code: 'INVALID_SCHEMA', field: 'schema', message: 'Use pipsync.tradingview.paper-signal.v1.' });\n}\n\nif (value.environment === 'live') {\n  errors.push({ code: 'LIVE_MODE_REJECTED', field: 'environment', message: 'Live mode is not supported by this demo.' });\n} else if (!['paper', 'sandbox'].includes(value.environment)) {\n  errors.push({ code: 'INVALID_ENVIRONMENT', field: 'environment', message: 'Use paper or sandbox.' });\n}\n\nif (typeof value.signal_id !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._:-]{7,63}$/.test(value.signal_id)) {\n  errors.push({ code: 'INVALID_SIGNAL_ID', field: 'signal_id', message: 'Use 8-64 safe identifier characters.' });\n}\n\nif (typeof value.instrument !== 'string' || !/^[A-Z0-9][A-Z0-9._:/-]{2,19}$/.test(value.instrument)) {\n  errors.push({ code: 'INVALID_INSTRUMENT', field: 'instrument', message: 'Use a 3-20 character uppercase instrument.' });\n}\n\nif (!['BUY', 'SELL'].includes(value.direction)) {\n  errors.push({ code: 'INVALID_DIRECTION', field: 'direction', message: 'Use BUY or SELL.' });\n}\n\nconst positiveNumber = (candidate) => typeof candidate === 'number' && Number.isFinite(candidate) && candidate > 0;\nif (!positiveNumber(value.entry_price)) {\n  errors.push({ code: 'INVALID_ENTRY_PRICE', field: 'entry_price', message: 'Use a positive finite number.' });\n}\n\nfor (const field of ['stop_loss', 'take_profit']) {\n  if (Object.prototype.hasOwnProperty.call(value, field) && value[field] !== null && !positiveNumber(value[field])) {\n    errors.push({ code: `INVALID_${field.toUpperCase()}`, field, message: 'Use null or a positive finite number.' });\n  }\n}\n\nif (positiveNumber(value.entry_price) && positiveNumber(value.stop_loss)) {\n  if (value.direction === 'BUY' && value.stop_loss >= value.entry_price) {\n    errors.push({ code: 'INVALID_STOP_GEOMETRY', field: 'stop_loss', message: 'BUY stop loss must be below entry.' });\n  }\n  if (value.direction === 'SELL' && value.stop_loss <= value.entry_price) {\n    errors.push({ code: 'INVALID_STOP_GEOMETRY', field: 'stop_loss', message: 'SELL stop loss must be above entry.' });\n  }\n}\n\nif (positiveNumber(value.entry_price) && positiveNumber(value.take_profit)) {\n  if (value.direction === 'BUY' && value.take_profit <= value.entry_price) {\n    errors.push({ code: 'INVALID_TARGET_GEOMETRY', field: 'take_profit', message: 'BUY take profit must be above entry.' });\n  }\n  if (value.direction === 'SELL' && value.take_profit >= value.entry_price) {\n    errors.push({ code: 'INVALID_TARGET_GEOMETRY', field: 'take_profit', message: 'SELL take profit must be below entry.' });\n  }\n}\n\nif (typeof value.created_at !== 'string' || !Number.isFinite(Date.parse(value.created_at))) {\n  errors.push({ code: 'INVALID_CREATED_AT', field: 'created_at', message: 'Use an ISO 8601 timestamp.' });\n}\n\nconst accepted = errors.length === 0;\nconst liveRejected = errors.some((error) => error.code === 'LIVE_MODE_REJECTED');\nconst safeSignal = accepted\n  ? {\n      signal_id: value.signal_id,\n      environment: value.environment,\n      instrument: value.instrument,\n      direction: value.direction,\n      entry_price: value.entry_price,\n      stop_loss: value.stop_loss ?? null,\n      take_profit: value.take_profit ?? null,\n      created_at: value.created_at,\n    }\n  : null;\n\nreturn [{\n  json: {\n    httpStatus: accepted ? 200 : (liveRejected ? 403 : 400),\n    body: {\n      schema: 'pipsync.validation-result.v1',\n      accepted,\n      execution: 'disabled',\n      signal: safeSignal,\n      errors,\n      limitations: {\n        authentication: 'not implemented',\n        durableReplayProtection: 'not implemented',\n        downstreamExecution: 'not implemented',\n      },\n    },\n  },\n}];"
      },
      "id": "01000000-0000-4000-8000-000000000003",
      "name": "Normalize and Validate Paper Only",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -40,
        80
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json.body }}",
        "options": {
          "responseCode": "={{ $json.httpStatus }}"
        }
      },
      "id": "01000000-0000-4000-8000-000000000004",
      "name": "Return Validation Result",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        260,
        80
      ]
    }
  ],
  "connections": {
    "Synthetic TradingView Webhook": {
      "main": [
        [
          {
            "node": "Normalize and Validate Paper Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize and Validate Paper Only": {
      "main": [
        [
          {
            "node": "Return Validation Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "01000000-0000-4000-8000-000000000000",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

PipSync 01 - TradingView Paper Signal Validator. Webhook trigger; 4 nodes.

Source: https://github.com/pipsyncio/pipsync-n8n-templates/blob/main/workflows/01-tradingview-paper-signal-validator.json — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

General

Blotato-Api. Uses @blotato/n8n-nodes-blotato. Webhook trigger; 53 nodes.

@Blotato/N8N Nodes Blotato
General

Social Media Poster - Dual Trigger. Uses @blotato/n8n-nodes-blotato. Webhook trigger; 23 nodes.

@Blotato/N8N Nodes Blotato
General

Odoo Customers API – Export to JSON or Excel provides a simple way to fetch customer records from your Odoo database and get them back either as a structured JSON response or a downloadable Excel (.xl

Odoo
General

Bridge the gap between Monday.com and Jira with this intelligent n8n automation template.

Jira, Monday.com
General

Community Node Disclaimer: This workflow uses KlickTipp community nodes.

N8N Nodes Klicktipp