> ## Documentation Index
> Fetch the complete documentation index at: https://docs.into.space/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamic Fee Curve

> How trading fees adjust with market certainty

export const MarketOrderFees = () => {
  const [hoveredLine, setHoveredLine] = useState(null);
  const [mousePos, setMousePos] = useState(null);
  const [isTouching, setIsTouching] = useState(false);
  const [isVisible, setIsVisible] = useState(false);
  const svgRef = useRef(null);
  const containerRef = useRef(null);
  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        setIsVisible(true);
      }
    }, {
      threshold: 0.2
    });
    if (containerRef.current) {
      observer.observe(containerRef.current);
    }
    return () => observer.disconnect();
  }, []);
  const generateBuyFeeData = () => {
    const points = [];
    const Fmax = 2.00;
    const Fmin = 0.02;
    const alpha = 1.3;
    for (let i = 0; i <= 100; i++) {
      const p = i;
      const fee = Fmin + (Fmax - Fmin) * (1 - Math.pow(p / 100, alpha));
      const svgX = 80 + p / 100 * 480;
      const svgY = 320 - fee / 2.05 * 280;
      points.push({
        probability: p,
        fee: fee.toFixed(3),
        svgX,
        svgY
      });
    }
    return points;
  };
  const generateSellFeeData = () => {
    const points = [];
    const Fpeak = 1.00;
    const Fmin = 0.02;
    const sigma = 25;
    for (let i = 0; i <= 100; i++) {
      const p = i;
      const fee = Fmin + (Fpeak - Fmin) * Math.exp(-0.5 * Math.pow((p - 50) / sigma, 2));
      const svgX = 80 + p / 100 * 480;
      const svgY = 320 - fee / 2.05 * 280;
      points.push({
        probability: p,
        fee: fee.toFixed(3),
        svgX,
        svgY
      });
    }
    return points;
  };
  const feeLines = [{
    type: 'buy',
    color: '#5EDD2C',
    label: 'Buy-Side Fee',
    points: generateBuyFeeData(),
    pathData: generateBuyFeeData().map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.svgX} ${p.svgY}`).join(' ')
  }, {
    type: 'sell',
    color: '#3B7DD8',
    label: 'Sell-Side Fee',
    points: generateSellFeeData(),
    pathData: generateSellFeeData().map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.svgX} ${p.svgY}`).join(' ')
  }];
  const updateInteraction = (clientX, clientY) => {
    if (!svgRef.current) return;
    const rect = svgRef.current.getBoundingClientRect();
    const svgX = (clientX - rect.left) / rect.width * 600;
    const svgY = (clientY - rect.top) / rect.height * 400;
    if (svgX >= 80 && svgX <= 560 && svgY >= 40 && svgY <= 320) {
      if (!isTouching) {
        setMousePos({
          x: svgX,
          y: svgY
        });
      }
      const probability = Math.round((svgX - 80) / 480 * 100);
      let closestLine = null;
      let minDistance = Infinity;
      feeLines.forEach(line => {
        if (line.points[probability]) {
          const distance = Math.abs(svgY - line.points[probability].svgY);
          if (distance < minDistance && distance < 40) {
            minDistance = distance;
            closestLine = {
              ...line,
              point: line.points[probability]
            };
          }
        }
      });
      setHoveredLine(closestLine);
    } else {
      if (!isTouching) {
        setMousePos(null);
      }
      setHoveredLine(null);
    }
  };
  const handleMouseMove = e => {
    if (!isTouching) {
      updateInteraction(e.clientX, e.clientY);
    }
  };
  const handleMouseLeave = () => {
    if (!isTouching) {
      setMousePos(null);
      setHoveredLine(null);
    }
  };
  const handleTouchStart = e => {
    e.preventDefault();
    setIsTouching(true);
    const touch = e.touches[0];
    updateInteraction(touch.clientX, touch.clientY);
  };
  const handleTouchMove = e => {
    e.preventDefault();
    const touch = e.touches[0];
    updateInteraction(touch.clientX, touch.clientY);
  };
  const handleTouchEnd = () => {
    setIsTouching(false);
    setMousePos(null);
    setTimeout(() => {
      if (isTouching === false) {
        setHoveredLine(null);
      }
    }, 3000);
  };
  const getTooltipProps = line => {
    if (!line || !line.point) return {};
    let x = line.point.svgX - 60;
    let y = line.point.svgY - 60;
    if (x < 10) x = 10;
    if (x > 470) x = 470;
    if (y < 10) y = line.point.svgY + 20;
    return {
      x,
      y
    };
  };
  const tooltipProps = getTooltipProps(hoveredLine);
  return <div ref={containerRef} className="w-full max-w-full">
      <div className="text-center mb-0">
        <h2 className="text-xl font-semibold mb-2">Market Order Fees</h2>
      </div>
      
      <div className="w-full">
        <svg ref={svgRef} width="100%" height="auto" viewBox="0 0 600 400" preserveAspectRatio="xMidYMid meet" className="bg-transparent cursor-crosshair w-full h-auto touch-none" style={{
    minHeight: '300px',
    maxHeight: '500px'
  }} onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave} onTouchStart={handleTouchStart} onTouchMove={handleTouchMove} onTouchEnd={handleTouchEnd}>
          <defs>
            <linearGradient id="gradientBuy" x1="0%" y1="0%" x2="0%" y2="100%">
              <stop offset="0%" stopColor="#5EDD2C" stopOpacity="0.4">
                <animate attributeName="stop-opacity" values="0.4;0.5;0.4" dur="4s" repeatCount="indefinite" />
              </stop>
              <stop offset="100%" stopColor="#5EDD2C" stopOpacity="0.067">
                <animate attributeName="stop-opacity" values="0.067;0.1;0.067" dur="4s" repeatCount="indefinite" />
              </stop>
            </linearGradient>
            <linearGradient id="gradientSell" x1="0%" y1="0%" x2="0%" y2="100%">
              <stop offset="0%" stopColor="#3B7DD8" stopOpacity="0.4">
                <animate attributeName="stop-opacity" values="0.4;0.5;0.4" dur="4s" repeatCount="indefinite" />
              </stop>
              <stop offset="100%" stopColor="#3B7DD8" stopOpacity="0.067">
                <animate attributeName="stop-opacity" values="0.067;0.1;0.067" dur="4s" repeatCount="indefinite" />
              </stop>
            </linearGradient>
            <pattern id="feeGrid" width="60" height="35" patternUnits="userSpaceOnUse">
              <path d="M 60 0 L 0 0 0 35" fill="none" stroke="currentColor" strokeWidth="1" strokeDasharray="3,3" opacity="0.3" />
            </pattern>
            <filter id="dropShadow">
              <feDropShadow dx="0" dy="2" stdDeviation="3" floodOpacity="0.3" />
            </filter>
          </defs>
          
          {}
          <rect width="480" height="280" x="80" y="40" fill="url(#feeGrid)" />
          
          {}
          {mousePos && <g opacity="0.4">
              <line x1="80" y1={mousePos.y} x2="560" y2={mousePos.y} stroke="currentColor" strokeWidth="1" strokeDasharray="2,2" />
              <line x1={mousePos.x} y1="40" x2={mousePos.x} y2="320" stroke="currentColor" strokeWidth="1" strokeDasharray="2,2" />
            </g>}
          
          {}
          <line x1="80" y1="320" x2="560" y2="320" stroke="currentColor" strokeWidth="2" opacity="0.6" />
          <line x1="80" y1="40" x2="80" y2="320" stroke="currentColor" strokeWidth="2" opacity="0.6" />
          
          {}
          <line x1="320" y1="40" x2="320" y2="320" stroke="currentColor" strokeWidth="2" strokeDasharray="8,4" opacity="0.6">
            <animate attributeName="stroke-dashoffset" values="-12;0" dur="1.5s" repeatCount="indefinite" />
          </line>
          
          {}
          {feeLines.map((line, index) => {
    const gradientId = line.type === 'buy' ? 'gradientBuy' : 'gradientSell';
    const areaPath = `${line.pathData} L 560 320 L 80 320 Z`;
    return <g key={index}>
                <path d={areaPath} fill={`url(#${gradientId})`} opacity={hoveredLine && hoveredLine.type !== line.type ? 0.3 : 1} className="transition-all duration-300" style={{
      animation: isVisible ? `fadeIn 1.6s ease-out ${index * 0.4}s both` : 'none'
    }} />
                <path d={line.pathData} fill="none" stroke={line.color} strokeWidth={hoveredLine?.type === line.type ? "4" : "3"} className="transition-all duration-300" opacity={hoveredLine && hoveredLine.type !== line.type ? 0.4 : 1} strokeDasharray="1200" strokeDashoffset={isVisible ? "0" : "1200"} style={{
      transition: isVisible ? `stroke-dashoffset 3s ease-out ${index * 0.4}s` : 'none'
    }} />
              </g>;
  })}
          
          {}
          {feeLines.map((line, index) => <g key={`interactive-${index}`}>
              {line.points.filter((_, i) => i % 2 === 0).map((point, i) => <circle key={i} cx={point.svgX} cy={point.svgY} r="8" fill="transparent" className="cursor-pointer" />)}
            </g>)}
          
          {}
          <text x="80" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.7">0</text>
          <text x="176" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.7">20</text>
          <text x="272" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.7">40</text>
          <text x="320" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.9" fontWeight="bold">50</text>
          <text x="368" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.7">60</text>
          <text x="464" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.7">80</text>
          <text x="560" y="340" fill="currentColor" fontSize="12" textAnchor="middle" opacity="0.7">100</text>
          
          {}
          <text x="70" y="325" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">0.00</text>
          <text x="70" y="290" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">0.25</text>
          <text x="70" y="250" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">0.50</text>
          <text x="70" y="210" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">0.75</text>
          <text x="70" y="170" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">1.00</text>
          <text x="70" y="130" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">1.25</text>
          <text x="70" y="90" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">1.50</text>
          <text x="70" y="50" fill="currentColor" fontSize="12" textAnchor="end" opacity="0.7">2.00</text>
          
          {}
          <text x="320" y="370" fill="currentColor" fontSize="14" textAnchor="middle" opacity="0.8">Market Probability (YES %)</text>
          <text x="30" y="180" fill="currentColor" fontSize="14" textAnchor="middle" transform="rotate(-90 30 180)" opacity="0.8">Fee (%)</text>
          
          {}
          <g transform="translate(420, 60)">
            <rect x="-15" y="-15" width="160" height="70" fill="currentColor" opacity="0" rx="6" />
            {feeLines.map((line, index) => <g key={index} transform={`translate(0, ${index * 25})`}>
                <line x1="0" y1="0" x2="20" y2="0" stroke={line.color} strokeWidth="3" />
                <text x="25" y="4" fill="currentColor" fontSize="12" opacity="0.8">{line.label}</text>
              </g>)}
          </g>
          
          {}
          <g>
            {}
            <text x="85" y="85" fill="currentColor" fontSize="11" opacity="0.7">Early phase:</text>
            <text x="85" y="100" fill="currentColor" fontSize="11" opacity="0.7">High buy fee (2%)</text>
            
            {}
            <text x="270" y="110" fill="currentColor" fontSize="11" opacity="0.7">Midpoint uncertainty:</text>
            <text x="270" y="125" fill="currentColor" fontSize="11" opacity="0.7">Sell fee peaks near 50%</text>
            
            {}
            <text x="430" y="300" fill="currentColor" fontSize="11" opacity="0.7">Certainty phase:</text>
            <text x="430" y="315" fill="currentColor" fontSize="11" opacity="0.7">Minimal fees (0.02%)</text>
          </g>
          
          {}
          {hoveredLine && hoveredLine.point && <g filter="url(#dropShadow)">
              <rect x={tooltipProps.x} y={tooltipProps.y} width="120" height="55" fill="#1a1a1a" stroke={hoveredLine.color} strokeWidth="2" rx="6" opacity="0.95" />
              <text x={tooltipProps.x + 60} y={tooltipProps.y + 18} fill="#ffffff" fontSize="12" textAnchor="middle" fontWeight="500">
                {hoveredLine.point.probability}% probability
              </text>
              <text x={tooltipProps.x + 60} y={tooltipProps.y + 32} fill={hoveredLine.color} fontSize="12" textAnchor="middle" fontWeight="500">
                {hoveredLine.type === 'buy' ? 'Buy Fee' : 'Sell Fee'}
              </text>
              <text x={tooltipProps.x + 60} y={tooltipProps.y + 46} fill={hoveredLine.color} fontSize="12" textAnchor="middle" fontWeight="bold">
                {hoveredLine.point.fee}%
              </text>
            </g>}
        </svg>
      </div>
      
      <style jsx>{`
        @keyframes fadeIn {
          from {
            opacity: 0;
          }
          to {
            opacity: 1;
          }
        }
      `}</style>
    </div>;
};

The Space Dynamic Fee Curve is designed as an incentive alignment mechanism for [makers & takers](/concepts/makers-takers) which uses fee asymmetry in order to achieve the following:

* Reward early participation, conviction and risk taking
* Maintain orderly books
* Reward makers for providing deeper liquidity (see: [rewards](/features/rewards))
* Incentivize consistent, long term participation
* Punish market manipulation

<MarketOrderFees />

<Note>
  Traders adding liquidity to the order book via limit orders (makers) pay 0 fees. The below fees only apply to market orders that get filled instantly (takers)
</Note>

1. **Buy Fee**: when a market order position is opened, fees start higher during uncertain phases of the market where your odds are highest and gradually decrease as the market gains more certainty

$$
F_{\text{buy}} (p) = F_{\text{min}} + (F_{\text{max}} - F_{\text{min}}) \times (1-(p/100)^{\alpha})
$$

where

* $F_{\text{buy}} (p)$: Buy-side fee at probability $p \%$
* $F_{\text{max}} = 2.00\%$: Maximum fee at $0\%$ probability (highest uncertainty)
* $F_{\text{min}} = 0.02\%$: Minimum fee at $100\%$ probability (certainty)
* $\alpha = 1.3$: Curve-shape coefficient (controls smoothness of decline)\
  \
  **Example:** \
  At $p = 20\%$, $F_{\text{buy}}(20) \approx 1.76\%$ but you're buying contracts that could pay out \$1 (400% ROI) so your odds are better \
  At $p = 80\%$, $F_{\text{buy}}(80) \approx 0.10\%$ you'll pay a 0.05% buy fee but your upside is smaller at \$0.25 (25% ROI) as your odds are worse

2. **Sell Fee:** if you wait until the market is resolved or you place a limit order to exit that doesn't get triggered immediately you are a maker and therefore do not pay any fee. However, if you want to close your position early via a market order, you need to understand that fees peak near the midpoint (at 50% probably or \$0.50) where uncertainty and volatility are highest; neither YES or NO sides have a clear informational advantage. This is the point where price manipulation and short-term flipping are most likely to occur therefore in order to protect market integrity and stabilize pricing, fees are highest (1%) and taper off towards either side as outcomes become more certain (0.02%).

   $$
   F_{\text{sell}} (p) = F_{\text{min}} + (F_{\text{peak}} - F_{\text{min}}) \times e^{-0.5 (\frac{p-50}{\sigma})^2}
   $$

   where

   * $F_{\text{sell}} (p)$: Sell-side fee at probability $p \%$
   * $F_{\text{peak}} = 1.00\%$: Maximum fee at $50\%$ probability (maximum uncertainty)
   * $F_{\text{min}} = 0.02\%$: Minimum fee at $100\%$ probability (certainty)
   * $\alpha = 1.3$: Curve-shape coefficient (controls smoothness of decline)

   At \$0.50 (50% probability) your sell fee is 1%

   At \$0.20 (20% probability) your sell fee is approximately 0.12%\
   \
   **Example:**\
   You wish to enter the trade below via a market order (if you entered via limit order you wouldn't pay any fee).

|                                | **Value**                                      |
| -----------------------------: | ---------------------------------------------- |
|                 **Order Type** | Market (fee applies; limit orders have no fee) |
|                     **Market** | "Will BTC close above \$150,000 this year?"    |
|          **Current BTC Price** | \$125,000                                      |
| **Current Market Probability** | 30%                                            |
|              **Shares to Buy** | 1,000 YES shares at \$0.30                     |

<Steps>
  <Step title="Opening your position" titleSize="h3">
    * Position size: 1,000 x \$0.30 = \$300
    * Buy fee  ≈ 1.6% (\$4.80)
    * **Total cost:** \$304.80
  </Step>

  <Step title="If you wish to close your position, before market resolution" titleSize="h3">
    * BTC rallies to \$145 and market probability rises to 80%
    * Sell price: \$0.80 x 1,000 = \$800
    * Sell fee  ≈ 0.04% (\$0.32)
    * Net proceeds: \$799.68
    * **Net profit:** \$800 - \$0.32 - \$304.80 = \$494.88 (162% ROI)
  </Step>
</Steps>
