dfs-optimizer

star 3

Build optimal Daily Fantasy Sports lineups for DraftKings and FanDuel. Maximize projected points under salary cap constraints for NBA, NFL, and MLB slates.

ianalloway By ianalloway schedule Updated 2/24/2026

name: dfs-optimizer description: "Build optimal Daily Fantasy Sports lineups for DraftKings and FanDuel. Maximize projected points under salary cap constraints for NBA, NFL, and MLB slates." homepage: https://github.com/ianalloway/openclaw-skills metadata: { "openclaw": { "emoji": "๐Ÿ†", "requires": { "bins": ["python3"] }, "credentials": [], },

}

DFS Lineup Optimizer

Build mathematically optimal Daily Fantasy Sports lineups. Uses a greedy salary-cap optimizer to maximize projected fantasy points under DraftKings/FanDuel roster constraints. No paid API needed โ€” paste your own projections or use the built-in samples.

NBA DraftKings Optimizer

python3 -c "
import itertools, json

# =====================================================
# PASTE YOUR SLATE HERE
# Format: (name, position, salary, projected_points)
# Positions: PG, SG, SF, PF, C, G (PG/SG), F (SF/PF), UTIL (any)
# DraftKings NBA: 2 PG, 2 SG, 2 SF, 1 PF, 1 C = 8 players, \$50,000 cap
# =====================================================
players = [
    ('LeBron James',     'SF', 9800, 52.4),
    ('Stephen Curry',    'PG', 9600, 51.8),
    ('Nikola Jokic',     'C',  9900, 58.1),
    ('Luka Doncic',      'PG', 10200, 59.2),
    ('Jayson Tatum',     'SF', 9200, 49.3),
    ('Anthony Davis',    'PF', 9400, 53.7),
    ('Ja Morant',        'PG', 8600, 46.2),
    ('Kevin Durant',     'SF', 8800, 47.5),
    ('Joel Embiid',      'C',  9500, 55.0),
    ('Trae Young',       'PG', 8200, 44.1),
    ('Devin Booker',     'SG', 8400, 45.3),
    ('Bam Adebayo',      'C',  7800, 41.2),
    ('DeMar DeRozan',    'SF', 7200, 38.5),
    ('Miles Bridges',    'SF', 6800, 36.1),
    ('Tyrese Haliburton','PG', 8000, 43.7),
    ('Jordan Poole',     'SG', 6200, 32.8),
    ('Franz Wagner',     'SF', 7000, 37.9),
    ('Alperen Sengun',   'C',  7400, 39.8),
    ('Brandon Ingram',   'SF', 7600, 40.5),
    ('Cole Anthony',     'PG', 5600, 28.4),
]

SALARY_CAP = 50000
ROSTER = {'PG': 2, 'SG': 2, 'SF': 2, 'PF': 1, 'C': 1}

def greedy_lineup(players, cap, roster_req):
    # Value = pts per \$1000 salary
    valued = [(name, pos, sal, pts, pts / sal * 1000) for name, pos, sal, pts in players]
    valued.sort(key=lambda x: -x[4])  # sort by value desc

    lineup = []
    remaining_slots = dict(roster_req)
    total_salary = 0
    total_pts = 0

    for name, pos, sal, pts, val in valued:
        if remaining_slots.get(pos, 0) > 0 and total_salary + sal <= cap:
            lineup.append((name, pos, sal, pts, val))
            remaining_slots[pos] -= 1
            total_salary += sal
            total_pts += pts
            if all(v == 0 for v in remaining_slots.values()):
                break

    return lineup, total_salary, total_pts

lineup, total_sal, total_pts = greedy_lineup(players, SALARY_CAP, ROSTER)

print('=== DraftKings NBA Optimal Lineup ===')
print(f'{\"Name\":<22} {\"POS\":<5} {\"SALARY\":>8} {\"PROJ\":>7} {\"VALUE\":>8}')
print('-' * 58)
for name, pos, sal, pts, val in sorted(lineup, key=lambda x: list(ROSTER.keys()).index(x[1]) if x[1] in ROSTER else 99):
    print(f'{name:<22} {pos:<5} \${sal:>7,} {pts:>7.1f} {val:>7.2f}x')
print('-' * 58)
print(f'{\"TOTAL\":<22} {\"\":<5} \${total_sal:>7,} {total_pts:>7.1f}')
print(f'Salary remaining: \${SALARY_CAP - total_sal:,}')
"

NFL DraftKings Optimizer

python3 -c "
# DraftKings NFL: 1 QB, 2 RB, 3 WR, 1 TE, 1 FLEX (RB/WR/TE), 1 DST
# Cap: \$50,000

players = [
    # (name, position, salary, projected_pts)
    ('Patrick Mahomes', 'QB',  8400, 32.1),
    ('Josh Allen',      'QB',  8800, 33.8),
    ('Christian McCaffrey', 'RB', 9200, 38.4),
    ('Austin Ekeler',   'RB',  6800, 26.2),
    ('Breece Hall',     'RB',  7400, 28.9),
    ('Isiah Pacheco',   'RB',  6200, 24.5),
    ('Tyreek Hill',     'WR',  9000, 35.2),
    ('Stefon Diggs',    'WR',  7600, 29.8),
    ('Davante Adams',   'WR',  8200, 32.6),
    ('Jaylen Waddle',   'WR',  7000, 27.4),
    ('Travis Kelce',    'TE',  8600, 34.5),
    ('Mark Andrews',    'TE',  7200, 28.1),
    ('San Francisco 49ers', 'DST', 4200, 12.4),
    ('Kansas City Chiefs', 'DST', 3800, 11.2),
    ('Dallas Cowboys',  'DST', 3600, 10.8),
    ('Ja\'Marr Chase',   'WR',  8600, 34.1),
    ('Alvin Kamara',    'RB',  7000, 27.6),
    ('Sam LaPorta',     'TE',  5800, 22.3),
]

SALARY_CAP = 50000
SLOTS = [('QB', 1), ('RB', 2), ('WR', 3), ('TE', 1), ('DST', 1)]
FLEX_POSITIONS = {'RB', 'WR', 'TE'}

def optimize_nfl(players, cap, slots, flex_count=1):
    from collections import defaultdict
    by_pos = defaultdict(list)
    for p in players:
        name, pos, sal, pts = p
        by_pos[pos].append((name, pos, sal, pts, pts / sal * 1000))
    for pos in by_pos:
        by_pos[pos].sort(key=lambda x: -x[4])

    lineup = []
    total_sal = 0
    total_pts = 0

    for pos, count in slots:
        added = 0
        for player in by_pos[pos]:
            if added >= count: break
            if total_sal + player[2] > cap: continue
            lineup.append(player)
            total_sal += player[2]
            total_pts += player[3]
            added += 1

    # Flex slot
    flex_candidates = []
    in_lineup = {p[0] for p in lineup}
    for pos in FLEX_POSITIONS:
        for p in by_pos[pos]:
            if p[0] not in in_lineup:
                flex_candidates.append(p)
    flex_candidates.sort(key=lambda x: -x[4])
    for p in flex_candidates:
        if total_sal + p[2] <= cap:
            lineup.append(p)
            total_sal += p[2]
            total_pts += p[3]
            break

    return lineup, total_sal, total_pts

lineup, total_sal, total_pts = optimize_nfl(players, SALARY_CAP, SLOTS)

print('=== DraftKings NFL Optimal Lineup ===')
print(f'{\"Name\":<26} {\"POS\":<5} {\"SALARY\":>8} {\"PROJ\":>7}')
print('-' * 52)
for name, pos, sal, pts, val in lineup:
    print(f'{name:<26} {pos:<5} \${sal:>7,} {pts:>7.1f}')
print('-' * 52)
print(f'{\"TOTAL\":<26} {\"\":<5} \${total_sal:>7,} {total_pts:>7.1f}')
"

Stacking Calculator

NFL DFS rewards correlated lineups โ€” QB + receiver from same game:

python3 -c "
# Stack value: extra points from correlated plays in the same game
def stack_value(qb_proj, wr_proj, correlation=0.35):
    '''
    Correlation bonus โ€” when QB plays well, his WR often does too.
    Expected additional points from stacking vs. independent picks.
    '''
    import math
    stack_bonus = correlation * math.sqrt(qb_proj * wr_proj) * 0.15
    return stack_bonus

stacks = [
    ('Josh Allen',    'Stefon Diggs',   33.8, 29.8),
    ('Patrick Mahomes', 'Travis Kelce', 32.1, 34.5),
    ('Ja\'Marr Chase', 'Joe Burrow',    34.1, 30.2),
]

print('=== Stack Analysis ===')
print(f'{\"QB\":<18} {\"WR/TE\":<18} {\"Combined\":>10} {\"Stack Bonus\":>12} {\"Total\":>8}')
print('-' * 72)
for qb, wr, qb_pts, wr_pts in stacks:
    bonus = stack_value(qb_pts, wr_pts)
    total = qb_pts + wr_pts + bonus
    print(f'{qb:<18} {wr:<18} {qb_pts+wr_pts:>10.1f} {bonus:>+11.2f} {total:>8.1f}')

print()
print('Rule: Stack a QB with his top receiver + the opposing team\'s best WR (game stack).')
"

Ownership & Leverage

Low-ownership plays win big tournaments. Find the right level of contrarian exposure:

python3 -c "
players = [
    # (name, pos, proj_pts, ownership_pct)
    ('Luka Doncic',     'PG', 59.2, 38.5),
    ('Nikola Jokic',    'C',  58.1, 35.2),
    ('Patrick Mahomes', 'QB', 32.1, 42.0),
    ('Travis Kelce',    'TE', 34.5, 28.4),
    ('Jordan Poole',    'SG', 32.8,  6.2),  # sneaky low ownership
    ('Cole Anthony',    'PG', 28.4,  4.1),  # punt play
]

def leverage_score(proj, ownership):
    '''Points above expected divided by ownership โ€” higher = more leverage in tournaments'''
    expected_points_at_ownership = ownership / 10  # crude baseline
    return (proj - expected_points_at_ownership * 2) / (ownership + 1) * 10

print('=== Ownership & Leverage Analysis ===')
print(f'{\"Player\":<22} {\"PROJ\":>6} {\"OWN%\":>6} {\"LEVERAGE\":>10} {\"PLAY TYPE\":>12}')
print('-' * 65)
for name, pos, proj, own in sorted(players, key=lambda x: -leverage_score(x[2], x[3])):
    lev = leverage_score(proj, own)
    if own < 10: play_type = '๐ŸŽฏ CONTRARIAN'
    elif own < 20: play_type = 'โšก LEVERAGE'
    elif own > 35: play_type = 'โš ๏ธ  CHALK'
    else: play_type = 'โœ… BALANCED'
    print(f'{name:<22} {proj:>6.1f} {own:>5.1f}% {lev:>+9.2f}  {play_type}')

print()
print('Cash games: Use chalk (high ownership) โ€” optimize for consistency')
print('Tournaments: Target 1-2 contrarian plays with strong projections')
"

Quick Reference

Format Salary Cap Roster
DK NBA $50,000 2PG/2SG/2SF/1PF/1C
DK NFL $50,000 1QB/2RB/3WR/1TE/1FLEX/1DST
DK MLB $50,000 2P/1C/1B/2B/3B/SS/3OF
FD NBA $60,000 2PG/2SG/2SF/1PF/1C
FD NFL $60,000 1QB/2RB/3WR/1TE/1FLEX/1K

Tips

  1. Always stack in tournaments โ€” correlated lineups have higher variance (good)
  2. Go contrarian on big slates โ€” 12+ game slates reward unique lineups
  3. Injury news is alpha โ€” late scratch creates value in replacement players
  4. Vegas totals matter โ€” high over/under games produce more fantasy points
  5. Never maximize ownership โ€” the crowd is already pricing in the obvious plays

Author

Created by Ian Alloway โ€” Data Scientist specializing in sports analytics and ML.

License

MIT License

Install via CLI
npx skills add https://github.com/ianalloway/openclaw-skills --skill dfs-optimizer
Repository Details
star Stars 3
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator