# ============================================================
# Trading Platform SPARQL Query Templates
# Version: 1.0.0
# ============================================================

PREFIX trade: <http://example.org/trading#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

# ============================================================
# Query 1: Generate Order Book from Ontology
# ============================================================
CONSTRUCT {
  ?orderBook a trade:OrderBook ;
             trade:hasInstrument ?instrument ;
             trade:hasBidSide ?bidSide ;
             trade:hasAskSide ?askSide ;
             trade:hasBestBid ?bestBid ;
             trade:hasBestAsk ?bestAsk ;
             trade:hasSpread ?spread .

  ?instrument a trade:Stock ;
              trade:symbol ?symbol ;
              trade:isin ?isin .

  ?bidSide trade:hasPriceLevel ?bidLevel .
  ?bidLevel a trade:BidLevel ;
            trade:price ?bidPrice ;
            trade:quantity ?bidQty .

  ?askSide trade:hasPriceLevel ?askLevel .
  ?askLevel a trade:AskLevel ;
            trade:price ?askPrice ;
            trade:quantity ?askQty .

  ?bestBid a trade:BestBid ;
           trade:price ?bestBidPrice ;
           trade:quantity ?bestBidQty .

  ?bestAsk a trade:BestAsk ;
           trade:price ?bestAskPrice ;
           trade:quantity ?bestAskQty .

  ?spread a trade:Spread ;
          trade:spreadValue ?spreadValue .
}
WHERE {
  BIND("AAPL" AS ?symbol)
  BIND("US0378331005" AS ?isin)
  BIND(150.00 AS ?bestBidPrice)
  BIND(100 AS ?bestBidQty)
  BIND(150.05 AS ?bestAskPrice)
  BIND(200 AS ?bestAskQty)
  BIND(?bestAskPrice - ?bestBidPrice AS ?spreadValue)
}

# ============================================================
# Query 2: Extract Order Book Price Levels
# ============================================================
SELECT ?symbol ?side ?price ?quantity
WHERE {
  ?orderBook trade:hasInstrument ?instrument ;
             trade:hasBidSide ?bidSide ;
             trade:hasAskSide ?askSide .

  ?instrument trade:symbol ?symbol .

  {
    ?bidSide trade:hasPriceLevel ?level .
    ?level trade:price ?price ;
           trade:quantity ?quantity .
    BIND("BID" AS ?side)
  }
  UNION
  {
    ?askSide trade:hasPriceLevel ?level .
    ?level trade:price ?price ;
           trade:quantity ?quantity .
    BIND("ASK" AS ?side)
  }
}
ORDER BY ?symbol DESC(?side) DESC(?price)

# ============================================================
# Query 3: Calculate Best Bid-Ask Spread
# ============================================================
SELECT ?symbol ?bestBid ?bestAsk ?spread (?spread / ?bestBid * 100 AS ?spreadBps)
WHERE {
  ?orderBook trade:hasInstrument ?instrument ;
             trade:hasBestBid ?bidLevel ;
             trade:hasBestAsk ?askLevel .

  ?instrument trade:symbol ?symbol .

  ?bidLevel trade:price ?bestBid .
  ?askLevel trade:price ?bestAsk .

  BIND(?bestAsk - ?bestBid AS ?spread)
}

# ============================================================
# Query 4: Find All Active Orders for Instrument
# ============================================================
SELECT ?orderID ?side ?type ?quantity ?price ?status
WHERE {
  ?order trade:hasInstrument ?instrument ;
         trade:orderID ?orderID ;
         trade:side ?side ;
         trade:quantity ?quantity ;
         trade:hasStatus ?statusObj .

  ?instrument trade:symbol "AAPL" .

  ?statusObj a ?type .
  ?type rdfs:subClassOf* trade:OrderStatus .

  BIND(STRAFTER(STR(?type), "#") AS ?status)

  OPTIONAL {
    ?order trade:limitPrice ?price .
  }

  FILTER(?status IN ("New", "PartiallyFilled"))
}

# ============================================================
# Query 5: Generate FIX New Order Single Message (35=D)
# ============================================================
CONSTRUCT {
  ?fixMsg a trade:NewOrderSingle ;
          trade:fixMsgType "D" ;
          trade:fixVersion "FIX.4.4" ;
          trade:hasOrder ?order .

  ?order a trade:LimitOrder ;
         trade:clientOrderID ?clOrdID ;
         trade:hasInstrument ?instrument ;
         trade:side ?side ;
         trade:quantity ?orderQty ;
         trade:limitPrice ?price ;
         trade:timeInForce ?tif ;
         trade:orderTimestamp ?transactTime .

  ?instrument trade:symbol ?symbol .
}
WHERE {
  BIND("ORD-12345" AS ?clOrdID)
  BIND("AAPL" AS ?symbol)
  BIND("BUY" AS ?side)
  BIND(100 AS ?orderQty)
  BIND(150.00 AS ?price)
  BIND("DAY" AS ?tif)
  BIND(NOW() AS ?transactTime)
}

# ============================================================
# Query 6: Calculate PnL for Position
# ============================================================
SELECT ?symbol ?positionQty ?entryPrice ?currentPrice ?unrealizedPnL ?pnlPercent
WHERE {
  ?position trade:hasInstrument ?instrument ;
            trade:positionQuantity ?positionQty ;
            trade:entryPrice ?entryPrice ;
            trade:unrealizedPnL ?unrealizedPnL .

  ?instrument trade:symbol ?symbol .

  ?orderBook trade:hasInstrument ?instrument ;
             trade:hasBestBid ?bestBid .

  ?bestBid trade:price ?currentPrice .

  BIND((?unrealizedPnL / (?entryPrice * ?positionQty)) * 100 AS ?pnlPercent)
}

# ============================================================
# Query 7: Find Orders Exceeding Position Limit
# ============================================================
SELECT ?orderID ?symbol ?orderQty ?currentPosition ?positionLimit ?excess
WHERE {
  ?order trade:orderID ?orderID ;
         trade:hasInstrument ?instrument ;
         trade:side "BUY" ;
         trade:quantity ?orderQty .

  ?instrument trade:symbol ?symbol ;
              trade:hasPositionLimit ?limitObj .

  ?limitObj trade:quantity ?positionLimit .

  ?position trade:hasInstrument ?instrument ;
            trade:positionQuantity ?currentPosition .

  BIND(?currentPosition + ?orderQty AS ?newPosition)
  BIND(?newPosition - ?positionLimit AS ?excess)

  FILTER(?newPosition > ?positionLimit)
}

# ============================================================
# Query 8: Market Data - Latest Ticks
# ============================================================
SELECT ?symbol ?tickPrice ?tickTime ?volume
WHERE {
  ?tick a trade:Tick ;
        trade:hasInstrument ?instrument ;
        trade:price ?tickPrice ;
        trade:tradeTimestamp ?tickTime ;
        trade:volume ?volume .

  ?instrument trade:symbol ?symbol .

  FILTER(?tickTime > NOW() - "PT5M"^^xsd:duration)
}
ORDER BY DESC(?tickTime)
LIMIT 100

# ============================================================
# Query 9: OHLCV Candles for Time Period
# ============================================================
SELECT ?symbol ?candleStart ?open ?high ?low ?close ?volume
WHERE {
  ?candle a trade:Candle ;
          trade:hasInstrument ?instrument ;
          trade:openPrice ?open ;
          trade:highPrice ?high ;
          trade:lowPrice ?low ;
          trade:closePrice ?close ;
          trade:volume ?volume ;
          trade:candleStartTime ?candleStart .

  ?instrument trade:symbol ?symbol .

  FILTER(?candleStart >= "2025-01-01T00:00:00"^^xsd:dateTime)
  FILTER(?candleStart < "2025-01-02T00:00:00"^^xsd:dateTime)
}
ORDER BY ?candleStart

# ============================================================
# Query 10: Find Execution Reports (FIX 35=8)
# ============================================================
SELECT ?orderID ?execID ?execType ?ordStatus ?side ?lastPx ?lastQty ?cumQty
WHERE {
  ?execReport a trade:ExecutionReport ;
              trade:fixMsgType "8" ;
              trade:hasOrder ?order ;
              trade:hasExecution ?exec .

  ?order trade:orderID ?orderID ;
         trade:side ?side ;
         trade:filledQuantity ?cumQty ;
         trade:hasStatus ?statusObj .

  ?statusObj rdfs:label ?ordStatus .

  ?exec trade:executionID ?execID ;
        trade:executionType ?execType ;
        trade:price ?lastPx ;
        trade:quantity ?lastQty .
}

# ============================================================
# Query 11: Calculate Total Exposure by Instrument
# ============================================================
SELECT ?symbol (SUM(?positionValue) AS ?totalExposure) (COUNT(?position) AS ?numPositions)
WHERE {
  ?position trade:hasInstrument ?instrument ;
            trade:positionQuantity ?qty ;
            trade:entryPrice ?price .

  ?instrument trade:symbol ?symbol .

  BIND(?qty * ?price AS ?positionValue)
}
GROUP BY ?symbol
ORDER BY DESC(?totalExposure)

# ============================================================
# Query 12: Find Options Near Expiration
# ============================================================
SELECT ?symbol ?optionType ?strikePrice ?expirationDate ?daysToExpiry
WHERE {
  ?option a trade:Option ;
          trade:symbol ?symbol ;
          trade:strikePrice ?strikePrice ;
          trade:expirationDate ?expirationDate .

  {
    ?option a trade:CallOption .
    BIND("CALL" AS ?optionType)
  }
  UNION
  {
    ?option a trade:PutOption .
    BIND("PUT" AS ?optionType)
  }

  BIND(xsd:integer((?expirationDate - CURRENT_DATE()) / "P1D"^^xsd:duration) AS ?daysToExpiry)

  FILTER(?daysToExpiry <= 7)
}
ORDER BY ?daysToExpiry

# ============================================================
# Query 13: Find Margin Requirements
# ============================================================
SELECT ?symbol ?positionQty ?marginAmount ?leverageRatio
WHERE {
  ?position trade:hasInstrument ?instrument ;
            trade:positionQuantity ?positionQty ;
            trade:leverageRatio ?leverageRatio ;
            trade:hasMarginRequirement ?marginReq .

  ?instrument trade:symbol ?symbol .

  ?marginReq trade:marginAmount ?marginAmount .
}

# ============================================================
# Query 14: Time and Sales (Trade Tape)
# ============================================================
SELECT ?symbol ?tradePrice ?tradeQty ?tradeTime
WHERE {
  ?trade a trade:Trade ;
         trade:hasInstrument ?instrument ;
         trade:tradePrice ?tradePrice ;
         trade:tradeQuantity ?tradeQty ;
         trade:tradeTimestamp ?tradeTime .

  ?instrument trade:symbol ?symbol .

  FILTER(?symbol = "AAPL")
}
ORDER BY DESC(?tradeTime)
LIMIT 50

# ============================================================
# Query 15: Calculate VaR for Portfolio
# ============================================================
SELECT ?portfolioID ?varValue ?confidenceLevel ?timeHorizon
WHERE {
  ?portfolio trade:hasRiskMetric ?var .

  ?var a trade:VaR ;
       trade:varValue ?varValue ;
       trade:confidenceLevel ?confidenceLevel ;
       trade:timeHorizon ?timeHorizon .

  BIND("PORTFOLIO-001" AS ?portfolioID)
}
