# GET Get Funding Info

### /get\_funding\_info

```json
/get_funding_info
```

**Example Query:**

```
https://base-hedger82.rasa.capital/get_funding_info
```

**Example Response:**

```json
  "BTCUSDT": {
    "next_funding_time": 1744070400000,
    "next_funding_rate_short": "0.000040455",
    "next_funding_rate_long": "-0.000053940",
    "funding_rate_epoch_duration": 14400
  },
  "FILUSDT": {
    "next_funding_time": 1744070400000,
    "next_funding_rate_short": "0.000045081",
    "next_funding_rate_long": "-0.000060108",
    "funding_rate_epoch_duration": 14400
  },

```

## Get Funding Info Rasa Implementation

### Router

```python
@common_router.get(
    '/get_funding_info',
    response_model=Dict[str, FundingInfoResponseSchema],
    dependencies=[
        Depends(CustomRateLimiter(times=1, seconds=1)),
        Depends(CustomRateLimiter(times=40, minutes=1)),
        Depends(CustomRateLimiter(times=1500, hours=1)),
    ]
)
async def get_funding_info(symbols: List[symbol_enum] = Query(None)):
    # symbols: optional list of tickers; defaults to BaseSymbols if None
    return get_funding_rates(symbols or BaseSymbols)
```

**Output**:

* Dict mapping ticker → `FundingInfoResponseSchema`.

```python
class FundingInfoResponseSchema(BaseModel):
    next_funding_time: int
    next_funding_rate_short: Decimal
    next_funding_rate_long: Decimal
```

### Data Sources

1. **Symbol table (DB)**
   * `Symbol.funding_rate_epoch_duration`
   * `Symbol.funding_rate_window_time`
2. **External exchange (Binance)**
   * `binance_client.futures_mark_price()` → `lastFundingRate`, `nextFundingTime`
3. **Hedger coefficients** (from `settings.py`)
   * `FundingRateHedgerToUserCoefficient`
   * `FundingRateUserToHedgerCoefficient`
4. **Positions table (DB)**
   * Used for filtering and in expressions (`Positions.position_type`, `Positions.opened_price`, etc.)

### Logic&#x20;

In short, the logic can be summarized like this:

```python
GET /get_funding_info
    ↓
get_funding_info(symbols) #Entry point 
    ↓
get_funding_rates(symbols)    
    ├─→ FundingRate.get_symbol_funding_details()
    ├    # read Symbol.is_valid from DB
    ├    # call binance_client.futures_mark_price()
    ├    # return List[SymbolFundingDetail]
    └─→ FundingRate.get_funding_details(..., to_apply=False)
    ├    # 1) build SQL CTE from symbol_funding_details
    ├    # 2) apply hedger’s long/short coefficients
    ├    # 3) compute contract_rate expression
    ├    # 4) group by Positions.party_a_address
    ├    # 5) optional $-amount filtering if to_apply=True
    ├    # 6) session.all_(stmt) → [FundingDetail(...)]
    ↓
map into Dict[str, FundingInfoResponseSchema]
    ↓
return JSON
```

**Fetch Symbol & Market Details**

```python
@staticmethod
def get_symbol_funding_details() -> List[SymbolFundingDetail]:
    # 1) Fetch mark‐price & funding‐time info for all symbols from Binance
    binance_markets: Dict[str, BinanceMarketDetail] = binance_client.futures_mark_price()

    # 2) Record current time (in seconds) to compare against each symbol’s funding window
    start_time = get_now_epoch()

    result: List[SymbolFundingDetail] = []
    # 3) Load every valid symbol row from your local Symbol table
    for symbol in session.scalars_all(
        Symbol.select().where(Symbol.is_valid.is_(true()))
    ):  

        # 4) Read the next funding timestamp (ms→s) from Binance’s data
        binance_next_funding_time = binance_markets[symbol.title].nextFundingTime // 1000
        
        # 5) Only keep symbols whose next funding falls within the on-chain funding window
        if binance_next_funding_time < start_time + symbol.funding_rate_window_time:
            symbol_funding_detail = SymbolFundingDetail(
                symbol_id                = symbol.symbol_id,
                binance_mark_price       = binance_markets[symbol.title].markPrice,
                binance_last_funding_rate= binance_markets[symbol.title].lastFundingRate,
                binance_next_funding_time= binance_next_funding_time,
                funding_rate_window_time = symbol.funding_rate_window_time,
            )

            # 7) Sanity check: confirm on-chain epoch aligns with Binance’s tick
            #    If it doesn’t, emit an alert and skip this symbol
            if binance_next_funding_time % symbol.funding_rate_epoch_duration != 0:
                send_instant_error_message(
                    title='Funding time of contract not compatible with Binance.',
                    amend=asdict(symbol_funding_detail)
                )
                continue

            # 8) Add to the list of symbols we’ll compute funding for
            result.append(symbol_funding_detail)

    # 9) Return all valid SymbolFundingDetail entries
    return result

```

**Coefficient Application Logic**

```python
@staticmethod
def get_funding_details(
    symbol_funding_details: List[SymbolFundingDetail],
    to_apply: bool = True
) -> Optional[List[FundingDetail]]:
    # 1) Build an in-SQL CTE of symbol timing & rates
    symbol_details_expr = values(
        column('symbol_id', Integer),
        column('price',     Numeric(**numeric_args)),
        column('funding_rate', Numeric(**numeric_args)),
        column('funding_window_open_time', BigInteger),
        column('binance_next_funding_time', BigInteger),
        name='funding_details'
    ).data([
        detail.get_data_for_cte()
        for detail in symbol_funding_details
    ])

    # 2) Apply hedger coefficients to raw funding_rate
    funding_rate_expr = symbol_details_expr.c.funding_rate * case(
        # SHORT & positive → hedger pays user (negate HedgerToUserCoef)
        (and_(Positions.position_type == PositionType.SHORT,
              symbol_details_expr.c.funding_rate >= 0),
         -FundingRateHedgerToUserCoefficient),

        # SHORT & negative → user pays hedger (negate UserToHedgerCoef)
        (and_(Positions.position_type == PositionType.SHORT,
              symbol_details_expr.c.funding_rate < 0),
         -FundingRateUserToHedgerCoefficient),

        # LONG & positive → user pays hedger
        (and_(Positions.position_type == PositionType.LONG,
              symbol_details_expr.c.funding_rate >= 0),
         FundingRateUserToHedgerCoefficient),

        # LONG & negative → hedger pays user
        (and_(Positions.position_type == PositionType.LONG,
              symbol_details_expr.c.funding_rate < 0),
         FundingRateHedgerToUserCoefficient)
    )

    # 3) Embed into full “contract rate” formula
    sign = case((Positions.position_type == PositionType.SHORT, -1), else_=1)
    contract_rate = func.round(
        (
            (
                (funding_rate_expr * symbol_details_expr.c.price)
                / (Positions.funding_rate_diff * Positions.opened_price)
                * sign + 1
            ) * Positions.funding_rate_diff - 1
        ) * sign,
        NumberFloatingPoint
    )

    # 4) Build query: group by counterparty (party A)
    stmt = Positions.select(
        Positions.party_a_address,
        func.json_agg(Positions.quote_id),
        func.json_agg(contract_rate)
    ).outerjoin(
        AppliedFundingRate, Positions.quote_id == AppliedFundingRate.quote_id
    ).join(Symbol).select_from(symbol_details_expr).join(
        symbol_details_expr,
        Symbol.symbol_id == symbol_details_expr.c.symbol_id
    ).where(
        AppliedFundingRate.id.is_(None),
        Positions.state.in_([PositionState.OPEN, PositionState.CLOSE_PENDING]),
        Positions.open_time <= symbol_details_expr.c.binance_next_funding_time,
        or_(
            Positions.last_funding_time < symbol_details_expr.c.funding_window_open_time,
            Positions.last_funding_time.is_(None)
        )
    ).group_by(Positions.party_a_address)

    # 5) If “to_apply”, also calculate $-amount and filter tiny ones
    if to_apply:
        funding_amount = (
            (Positions.quantity - Positions.filled_closed_amount)
            * Positions.opened_price * contract_rate
        )
        stmt = stmt.add_columns(
            func.json_agg(
                case(
                    (contract_rate > Positions.max_funding_rate,
                     Positions.max_funding_rate),
                    else_=contract_rate
                )
            ),
            func.sum(funding_amount).label('funding_amount')
        ).where(
            func.abs(funding_amount) > GasWorthyFundingThresholdPerPosition
        ).order_by(desc('funding_amount'))

    # 6) Execute and map to dataclass
    rows = session.all_(stmt)
    return [FundingDetail(*row) for row in rows]

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.symm.io/liquidity-provider-documentation/building-a-solver-on-symmio/5.-creating-the-apis/get-get-funding-info.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
