caishen

Express API

RISE Framework Specification

Spec ID: 30
Version: 1.0
Document ID: caishen-rise-api-v1.0
Last Updated: 2025-01-31

Creative Intent

What the Express API Enables Users to Create:

Desired Outcomes:

  1. External applications can consume Caishen data
  2. Data is available in multiple formats
  3. API is simple and intuitive
  4. Performance is optimized for common queries

API Overview

Base URL

http://localhost:3999

Authentication

Currently no authentication required (internal use only).


Endpoints

GET /cdb/:pov/:type?/:format?

Retrieve ChaosDataBuilder data for a POV.

Parameters: | Parameter | Type | Description | Default | |———–|——|————-|———| | pov | path | POV identifier (e.g., “EUR-USD_H4”) | required | | type | path | Data type to return | “bars” | | format | path | Output format | “csv” |

Type Options:

Format Options:

Examples:

# Get bar data as CSV
GET /cdb/EUR-USD_H4/bars/csv

# Get CDB summary as JSON
GET /cdb/EUR-USD_H4/cdb/json

# Get multi-timeframe perspective as JSON
GET /cdb/EUR-USD_H4/p/json

Response (bars/csv):

Dt,Open,High,Low,Close,Volume,Lips,Teeth,Jaw,AO,SAO,AC,ACD,AOF,Zone,BDB,xBdb,MFI,Squat,FractalBuy,FractalSell,FractalDim
2025-01-31T10:00:00Z,1.0850,1.0860,1.0845,1.0855,1234,1.0823,1.0815,1.0810,0.0012,0.0011,0.0003,1,0.0015,1,0,0,2,0,,1.0860,1.5

Response (cdb/json):

{
  "Instrument": "EUR/USD",
  "Timeframe": "H4",
  "TrendLastWave": "UP",
  "MarketOverViewerNodeCurrentIsDiverging": false,
  "PipSize": 0.0001,
  "PriceHighestValue": 1.0920,
  "PriceLowestValue": 1.0780,
  "AOHighestValue": 0.0035,
  "AOLowestValue": -0.0028,
  "NbBarMouthIsOpen": 12,
  "InstrumentProperty": {
    "Symbol": "EUR/USD",
    "mar": { "MMR": 0.02, "LMR": 0.01 },
    "pips": 0.0001
  }
}

Response (perspective/json):

{
  "Instrument": "EUR/USD",
  "InstrumentProperty": { ... },
  "Perspective": {
    "m5": { "Instrument": "EUR/USD", "Timeframe": "m5", ... },
    "m15": { "Instrument": "EUR/USD", "Timeframe": "m15", ... },
    "H1": { "Instrument": "EUR/USD", "Timeframe": "H1", ... },
    "H4": { "Instrument": "EUR/USD", "Timeframe": "H4", ... },
    "D1": { "Instrument": "EUR/USD", "Timeframe": "D1", ... },
    "W1": { "Instrument": "EUR/USD", "Timeframe": "W1", ... },
    "M1": { "Instrument": "EUR/USD", "Timeframe": "M1", ... }
  }
}

Static File Endpoints

GET /pds/:filename

Serve raw price data JSON files.

GET /pds/EUR-USD_H4.json

GET /ids/:filename

Serve indicator data JSON files.

GET /ids/EUR-USD_H4_indicators.json

GET /cds/:filename

Serve CDS DTO files.

GET /cds/EUR-USD_H4_cdb.json

Data Structures

CDB CSV Header

Instrument,Timeframe,InstrumentPerspectiveDataDivergenceIndicatorSequence,
MarketOverViewerNodeCurrentIsDiverging,MarketOverViewerNodeCurrentBdb,
MarketOverViewerNodeCurrentDivA,MarketOverViewerNodeCurrentDivAPeakDt,
MarketOverViewerNodeCurrentDivB,MarketOverViewerNodeCurrentDivBPeakDt,
MarketOverViewerNodeCurrentTrendLastWave,MarketOverViewerNodeCurrentDivergenceIndicator,
MarketOverViewerNodeCurrentStrenghtOrder,TrendLastWave,TrendLastBar,
PovTlid,CorrelationId,GatorMouthMaxOpenessMaxDistGLRL,GatorMouthMaxOpenessMaxDistRLBL,
GatorMouthMaxOpenessMaxDistGLBL,AngleGatorDatadistGLRL,AngleGatorDatadistRLBL,
AngleGatorDatadistGLBL,AngleGatorDatadistGLPrice,AngleGatorDatadistRLPrice,
AngleGatorDatadistBLPrice,AngleGatorDatadistPriceMaxPrice,AngleDataRelativezeddistGLRL,
AngleDataRelativezeddistRLBL,AngleDataRelativezeddistGLBL,AngleDataRelativezeddistGLPrice,
AngleDataRelativezeddistRLPrice,AngleDataRelativezeddistBLPrice,
AngleDataRelativezeddistPriceMaxPrice,AngleDsDataMaxAngleGatorDataMaxLipsTeethDiff,
AngleDsDataMaxAngleGatorDataMaxTeethJawDiff,AngleDsDataMaxAngleGatorDataMaxLipsJawDiff,
AngleDsDataMaxAngleGatorDataMaxPriceDistFromLips,AngleDsDataMaxAngleGatorDataMaxPriceDistFromTeeth,
AngleDsDataMaxAngleGatorDataMaxPriceDistFromJaw,AngleDsDataNbBarMouthIsOpen,
PipSize,PriceHighestValue,PriceLowestValue,AOHighestValue,AOLowestValue,
ACHighestValue,ACLowestValue,NbBarMouthIsOpen,IPMMR,IPLMR,IPpre,IPpips,IPcm,
IPtsmi,IPtsmx,IPsubs,IPbu,IPqtmi,IPqtmx,IPcc

Bar CSV Header

Dt,Open,High,Low,Close,Volume,Lips,Teeth,Jaw,AO,SAO,AC,ACD,AOF,Zone,BDB,xBdb,MFI,Squat,FractalBuy,FractalSell,FractalDim

Configuration

Port

Default: 3999

Data Directory

var cdbRootDir = path.join(__dirname, '/cdb-dto');

Supported Timeframes

var ContextTimeframes = ['m5', 'm15', 'H1', 'H4', 'D1', 'W1', 'M1'];

Creative Advancement Scenarios

Scenario 1: External Chart Integration

Creative Advancement Scenario: Load Data in External Tool

Desired Outcome: TradingView or custom app displays Caishen data

Current Reality: User wants to analyze in preferred tool

Natural Progression Steps:
  1. External app requests /cdb/EUR-USD_H4/bars/json
  2. API reads CDB from file
  3. JSON response returned
  4. App parses and renders data
  5. User sees chaos indicators in their tool

Achieved Outcome: Caishen data accessible anywhere

Supporting Features: JSON endpoint, CORS if needed

Scenario 2: Multi-Timeframe Dashboard

Creative Advancement Scenario: Build Trading Dashboard

Desired Outcome: Single view of all timeframes for instrument

Current Reality: Need to check each timeframe separately

Natural Progression Steps:
  1. Dashboard requests /cdb/EUR-USD_H4/p/json
  2. API loads all timeframe CDBs
  3. Perspective object returned
  4. Dashboard displays grid of timeframes
  5. User sees complete picture

Achieved Outcome: Comprehensive instrument view

Supporting Features: Perspective endpoint

Implementation Notes

Current Node.js Implementation

const express = require("express");
const fs = require("fs");
const path = require("path");

const app = express();
const port = 3999;
const cdbRootDir = path.join(__dirname, '/cdb-dto');
const ContextTimeframes = ['m5', 'm15', 'H1', 'H4', 'D1', 'W1', 'M1'];

app.get('/cdb/:pov/:t?/:outtype?', function(req, res) {
  const pov = req.params.pov;
  const t = req.params.t || "bars";
  const outtype = req.params.outtype || "csv";
  
  const cdb = readCDB(pov);
  let output = "";
  
  switch (outtype) {
    case "csv":
      if (t === "cdb" || t === "c") {
        output = getCDBCsvHeader() + "\n" + getCDBCsvLine(cdb);
      } else if (t === "bars" || t === "b") {
        output = getChaosBarCsvHeader();
        cdb.ChartBars.forEach(b => {
          output += "\n" + getChaosBarCsvLine(b);
        });
      }
      break;
    case "json":
      if (t === "cdb" || t === "c") {
        output = JSON.stringify(cdb);
      } else if (t === "cdbs" || t === "p") {
        const perspective = {};
        ContextTimeframes.forEach(tf => {
          try {
            const _pov = cdb.Instrument.replace("/", "-") + "_" + tf;
            perspective[tf] = readCDB(_pov);
          } catch (err) {
            console.log(`Warning: Could not load ${tf} timeframe data`);
          }
        });
        output = JSON.stringify({
          Instrument: cdb.Instrument,
          InstrumentProperty: cdb.InstrumentProperty,
          Perspective: perspective
        });
      }
      break;
  }
  
  res.send(output);
});

function readCDB(pov) {
  const filePath = path.join(cdbRootDir, pov + '.json');
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
}

app.listen(port, () => {
  console.log(`CaishenExpressAPI listening at http://localhost:${port}`);
});

Python FastAPI Implementation

from fastapi import FastAPI, HTTPException
from fastapi.responses import PlainTextResponse, JSONResponse
import json
from pathlib import Path
from typing import Optional

app = FastAPI(title="Caishen API", version="1.0")

CDB_ROOT_DIR = Path(__file__).parent / "cdb-dto"
CONTEXT_TIMEFRAMES = ['m5', 'm15', 'H1', 'H4', 'D1', 'W1', 'M1']

def read_cdb(pov: str) -> dict:
    file_path = CDB_ROOT_DIR / f"{pov}.json"
    if not file_path.exists():
        raise HTTPException(status_code=404, detail=f"POV {pov} not found")
    with open(file_path) as f:
        return json.load(f)

@app.get("/cdb/{pov}")
@app.get("/cdb/{pov}/{data_type}")
@app.get("/cdb/{pov}/{data_type}/{output_format}")
async def get_cdb(
    pov: str,
    data_type: str = "bars",
    output_format: str = "csv"
):
    cdb = read_cdb(pov)
    
    if output_format == "json":
        if data_type in ("cdb", "c"):
            return JSONResponse(cdb)
        elif data_type in ("cdbs", "p"):
            instrument = cdb.get("Instrument", "").replace("/", "-")
            perspective = {}
            for tf in CONTEXT_TIMEFRAMES:
                try:
                    perspective[tf] = read_cdb(f"{instrument}_{tf}")
                except FileNotFoundError:
                    # Timeframe data not available, skip it
                    pass
                except Exception as e:
                    # Log other errors for debugging
                    print(f"Warning: Could not load {tf} data: {e}")
            return JSONResponse({
                "Instrument": cdb.get("Instrument"),
                "InstrumentProperty": cdb.get("InstrumentProperty"),
                "Perspective": perspective
            })
    
    elif output_format == "csv":
        if data_type in ("bars", "b", "bar"):
            header = "Dt,Open,High,Low,Close,Volume,Lips,Teeth,Jaw,AO,SAO,AC,Zone"
            lines = [header]
            for bar in cdb.get("ChartBars", []):
                ask = bar.get("a", {})
                bid = bar.get("b", {})
                avg_o = (ask.get("o", 0) + bid.get("o", 0)) / 2
                avg_h = (ask.get("h", 0) + bid.get("h", 0)) / 2
                avg_l = (ask.get("l", 0) + bid.get("l", 0)) / 2
                avg_c = (ask.get("c", 0) + bid.get("c", 0)) / 2
                lines.append(
                    f"{bar.get('dt')},{avg_o},{avg_h},{avg_l},{avg_c},"
                    f"{bar.get('v',0)},{bar.get('l',0)},{bar.get('t',0)},"
                    f"{bar.get('j',0)},{bar.get('ao',0)},{bar.get('sa',0)},"
                    f"{bar.get('ac',0)},{bar.get('z',0)}"
                )
            return PlainTextResponse("\n".join(lines))
    
    raise HTTPException(status_code=400, detail="Invalid parameters")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=3999)

TypeScript Express Implementation

import express, { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';

const app = express();
const port = 3999;
const cdbRootDir = path.join(__dirname, 'cdb-dto');
const contextTimeframes = ['m5', 'm15', 'H1', 'H4', 'D1', 'W1', 'M1'];

interface ChaosDataBuilder {
  Instrument: string;
  Timeframe: string;
  ChartBars: BarChaosItem[];
  InstrumentProperty: any;
  [key: string]: any;
}

interface BarChaosItem {
  dt: string;
  a: { o: number; h: number; l: number; c: number };
  b: { o: number; h: number; l: number; c: number };
  v: number;
  l: number;
  t: number;
  j: number;
  ao: number;
  ac: number;
  z: number;
  [key: string]: any;
}

function readCDB(pov: string): ChaosDataBuilder {
  const filePath = path.join(cdbRootDir, `${pov}.json`);
  const data = fs.readFileSync(filePath, 'utf8');
  return JSON.parse(data);
}

app.get('/cdb/:pov/:type?/:format?', (req: Request, res: Response) => {
  const { pov, type = 'bars', format = 'csv' } = req.params;
  
  try {
    const cdb = readCDB(pov);
    
    if (format === 'json') {
      if (type === 'cdb' || type === 'c') {
        return res.json(cdb);
      }
      if (type === 'cdbs' || type === 'p') {
        const instrument = cdb.Instrument.replace('/', '-');
        const perspective: Record<string, ChaosDataBuilder> = {};
        for (const tf of contextTimeframes) {
          try {
            perspective[tf] = readCDB(`${instrument}_${tf}`);
          } catch (error) {
            // Timeframe data not available, continue with other timeframes
            console.log(`Warning: Could not load ${tf} timeframe data for ${instrument}`);
          }
        }
        return res.json({
          Instrument: cdb.Instrument,
          InstrumentProperty: cdb.InstrumentProperty,
          Perspective: perspective
        });
      }
    }
    
    if (format === 'csv') {
      if (type === 'bars' || type === 'b') {
        const header = 'Dt,Open,High,Low,Close,Volume,Lips,Teeth,Jaw,AO,AC,Zone';
        const lines = cdb.ChartBars.map(bar => {
          const o = (bar.a.o + bar.b.o) / 2;
          const h = (bar.a.h + bar.b.h) / 2;
          const l = (bar.a.l + bar.b.l) / 2;
          const c = (bar.a.c + bar.b.c) / 2;
          return `${bar.dt},${o},${h},${l},${c},${bar.v},${bar.l},${bar.t},${bar.j},${bar.ao},${bar.ac},${bar.z}`;
        });
        return res.send([header, ...lines].join('\n'));
      }
    }
    
    res.status(400).send('Invalid parameters');
  } catch (error) {
    res.status(404).send(`POV ${pov} not found`);
  }
});

app.listen(port, () => {
  console.log(`CaishenExpressAPI listening at http://localhost:${port}`);
});