{
  "id": "P085",
  "slug": "stock-chart",
  "key": "P085-stock-chart",
  "title": "Stock chart",
  "summary": "Daily prices in whole cents drawn as a chart: the best single buy and sell, which is the best run of daily changes (Kadane); every rise taken; and the best profit from at most k trades by dynamic programming, with the trades listed.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P085 - Stock chart\n\nDaily prices in whole cents, drawn as a chart. The program finds the best\nsingle buy and sell, which is the same as the best run of daily changes;\nthe profit from taking every rise; and the best profit from at most k\ntrades, with the trades listed. It starts with 16 days of prices.\n\n- `main.eml` - the menu, reading prices, the chart and the reports\n- `market.eml` - the best trade, the best run, daily changes, every rise,\n  and the best k trades\n\nHow each part works:\n\n- Best single trade, as in the corpus case `stock-buy-sell-profit`: one\n  pass, keeping the cheapest price so far. Not trading is allowed, so when\n  nothing rises the best is 0.\n- Best run, as in the corpus case `max-subarray-kadane`: the largest sum\n  of consecutive daily changes, keeping where the run starts. A trade's\n  profit is the sum of the changes it holds through, so with any rise the\n  two are the same. When every change is a fall, Kadane gives the\n  smallest fall, while the best trade is still 0.\n- Every rise: as many trades as you like means taking each day's rise.\n- At most k trades, one share at a time, by dynamic programming over the\n  days: the most made by day d with at most j trades is either the most by\n  the day before, or a sale on day d of a share bought on an earlier day\n  b, after the most made with j - 1 trades by day b. The trades are read\n  back from the choices made.\n- The chart scales each price to a bar of 1 to 40 # from the lowest to the\n  highest, in whole numbers.\n\nWhat is checked: menu choices 1 to 5; 1 to 5 trades; 2 to 40 prices, each\nabove 0 and up to 99999.99, with at most two decimals, separated by\nspaces. An empty answer cancels.\n\nSessions: `sessions/basic.in` gives:\n- the chart, and the best trade: buy on day 3, sell on day 15, 5.20 a\n  share, the same as the best run of changes;\n- at most 1, 2 and 5 trades: 5.20, 7.55 and 10.00, the last being every\n  rise;\n- prices that only fall (no trade, the smallest fall as the best run) and\n  prices that stay flat.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- 0, 6 and abc trades;\n- one price, a word, a negative price, 0, three decimals, \"12.\" and 41\n  prices - each refused, then cancelled.\n\nBuilt on the verified corpus cases `stock-buy-sell-profit` (the cheapest\nprice so far) and `max-subarray-kadane` (the best run, and why it differs\nwhen nothing rises).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P085 stock chart: daily prices drawn as a chart; the best single trade,\n# which is the best run of daily changes; and the best profit from up to k\n# trades, with the trades listed.\nimport market\n\ndef trim(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef cents_of(s):\n    # \"12.40\", \"12.4\" or \"12\" as whole cents (up to 99999.99), or -1.\n    0 => k\n    while k < len(s) and s[k] != \".\":\n        k + 1 => k\n    s[0:k] => whole\n    \"\" => part\n    if k < len(s):\n        s[k + 1:len(s)] => part\n    if len(whole) == 0 or len(whole) > 5 or len(part) > 2 or (k < len(s) and len(part) == 0):\n        return -1\n    0 => n\n    for c in whole + part:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    if len(part) == 0:\n        return n * 100\n    if len(part) == 1:\n        return n * 10\n    return n\n\ndef money(c):\n    if c < 0:\n        return \"-\" + money(0 - c)\n    0 => w\n    c => r\n    while r >= 100:\n        r - 100 => r\n        w + 1 => w\n    if r < 10:\n        return str(w) + \".0\" + str(r)\n    return str(w) + \".\" + str(r)\n\ndef prices_of(s):\n    [] => out\n    \"\" => w\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if w != \"\":\n                cents_of(w) => v\n                if v <= 0:\n                    return []\n                out + [v] => out\n            \"\" => w\n        else:\n            w + c => w\n    return out\n\ndef chart(ps):\n    # One row per day, a bar of up to 40 # from the lowest price to the\n    # highest.\n    ps[0] => lo\n    ps[0] => hi\n    for p in ps:\n        if p < lo:\n            p => lo\n        if p > hi:\n            p => hi\n    for d in [0:len(ps) - 1]:\n        1 => n\n        if hi > lo:\n            # 1 + floor((price - lowest) x 39 / (highest - lowest)), in\n            # whole numbers\n            (ps[d] - lo) * 39 => r\n            while r >= hi - lo:\n                r - (hi - lo) => r\n                n + 1 => n\n        \"\" => bar\n        for i in [1:n]:\n            bar + \"#\" => bar\n        \"\" => day\n        if d + 1 < 10:\n            \" \" => day\n        (\"  day \" + day + str(d + 1) + \"  \" + money(ps[d]) + \"  \" + bar) ^0\n\ndef best(ps):\n    market.best_trade(ps) => t\n    if t[0] == 0:\n        \"No single trade makes money: the price only falls (or stays). Not trading is the best.\" ^0\n    else:\n        (\"Best single trade: buy on day \" + str(t[1] + 1) + \" at \" + money(ps[t[1]]) + \", sell on day \" + str(t[2] + 1) + \" at \" + money(ps[t[2]]) + \" - \" + money(t[0]) + \" a share.\") ^0\n    market.changes(ps) => cs\n    market.best_run(cs) => r\n    (\"The best run of daily changes is days \" + str(r[1] + 1) + \" to \" + str(r[2] + 2) + \", adding up to \" + money(r[0]) + \".\") ^0\n    if r[0] > 0:\n        \"The same thing: a trade's profit is the sum of the daily changes it holds through.\" ^0\n    elif r[0] == 0:\n        \"No day rises, so the best run adds up to nothing - and the best trade is not to trade.\" ^0\n    else:\n        \"Every daily change is a fall, so the best run is the smallest fall - while the best trade is not to trade.\" ^0\n    (\"Trading every rise, as often as you like: \" + money(market.every_rise(ps)) + \".\") ^0\n\ndef trades(ps):\n    while True:\n        trim(input(\"at most how many trades (1 to 5)> \")) => s\n        if s == \"\":\n            \"Cancelled.\" ^0\n            return\n        if s == \"1\" or s == \"2\" or s == \"3\" or s == \"4\" or s == \"5\":\n            int(s) => k\n            market.best_k(ps, k) => r\n            if len(r[1]) == 0:\n                \"No trade makes money.\" ^0\n                return\n            for t in r[1]:\n                (\"  buy day \" + str(t[0] + 1) + \" at \" + money(ps[t[0]]) + \", sell day \" + str(t[1] + 1) + \" at \" + money(ps[t[1]]) + \": \" + money(ps[t[1]] - ps[t[0]])) ^0\n            \"trades\" => word\n            if k == 1:\n                \"trade\" => word\n            (\"At most \" + str(k) + \" \" + word + \", one share at a time: \" + money(r[0]) + \" in all.\") ^0\n            return\n        \"Type a whole number from 1 to 5.\" ^0\n\ndef new_prices(ps):\n    while True:\n        trim(input(\"prices, oldest first (2 to 40, like 12.40 13 11.85)> \")) => s\n        if s == \"\":\n            \"Cancelled.\" ^0\n            return ps\n        prices_of(s) => out\n        if len(out) >= 2 and len(out) <= 40:\n            (str(len(out)) + \" days of prices.\") ^0\n            return out\n        \"Type 2 to 40 prices above 0, up to 99999.99, separated by spaces.\" ^0\n\n[1250, 1310, 1180, 1225, 1405, 1390, 1530, 1480, 1295, 1350, 1610, 1575, 1440, 1520, 1700, 1655] => prices\n\n\"== Stock chart ==\" ^0\n\"Daily prices: the best single trade, the best run of changes, and the best k trades.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) chart  2) best trade  3) best k trades  4) new prices  5) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        chart(prices)\n    elif choice == \"2\":\n        best(prices)\n    elif choice == \"3\":\n        trades(prices)\n    elif choice == \"4\":\n        new_prices(prices) => prices\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n\"Bye.\" ^0\n",
      "python": "import market\n\ndef trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef cents_of(s):\n    k = 0\n    while k < len(s) and s[k] != \".\":\n        k = k + 1\n    whole = s[0:k]\n    part = \"\"\n    if k < len(s):\n        part = s[k + 1:len(s)]\n    if len(whole) == 0 or len(whole) > 5 or len(part) > 2 or k < len(s) and len(part) == 0:\n        return -1\n    n = 0\n    for c in whole + part:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    if len(part) == 0:\n        return n * 100\n    if len(part) == 1:\n        return n * 10\n    return n\n\ndef money(c):\n    if c < 0:\n        return \"-\" + money(0 - c)\n    w = 0\n    r = c\n    while r >= 100:\n        r = r - 100\n        w = w + 1\n    if r < 10:\n        return str(w) + \".0\" + str(r)\n    return str(w) + \".\" + str(r)\n\ndef prices_of(s):\n    out = []\n    w = \"\"\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if w != \"\":\n                v = cents_of(w)\n                if v <= 0:\n                    return []\n                out = out + [v]\n            w = \"\"\n        else:\n            w = w + c\n    return out\n\ndef chart(ps):\n    lo = ps[0]\n    hi = ps[0]\n    for p in ps:\n        if p < lo:\n            lo = p\n        if p > hi:\n            hi = p\n    for d in range(0, len(ps)):\n        n = 1\n        if hi > lo:\n            r = (ps[d] - lo) * 39\n            while r >= hi - lo:\n                r = r - (hi - lo)\n                n = n + 1\n        bar = \"\"\n        for i in range(1, n+1):\n            bar = bar + \"#\"\n        day = \"\"\n        if d + 1 < 10:\n            day = \" \"\n        print(\"  day \" + day + str(d + 1) + \"  \" + money(ps[d]) + \"  \" + bar)\n\ndef best(ps):\n    t = market.best_trade(ps)\n    if t[0] == 0:\n        print(\"No single trade makes money: the price only falls (or stays). Not trading is the best.\")\n    else:\n        print(\"Best single trade: buy on day \" + str(t[1] + 1) + \" at \" + money(ps[t[1]]) + \", sell on day \" + str(t[2] + 1) + \" at \" + money(ps[t[2]]) + \" - \" + money(t[0]) + \" a share.\")\n    cs = market.changes(ps)\n    r = market.best_run(cs)\n    print(\"The best run of daily changes is days \" + str(r[1] + 1) + \" to \" + str(r[2] + 2) + \", adding up to \" + money(r[0]) + \".\")\n    if r[0] > 0:\n        print(\"The same thing: a trade's profit is the sum of the daily changes it holds through.\")\n    elif r[0] == 0:\n        print(\"No day rises, so the best run adds up to nothing - and the best trade is not to trade.\")\n    else:\n        print(\"Every daily change is a fall, so the best run is the smallest fall - while the best trade is not to trade.\")\n    print(\"Trading every rise, as often as you like: \" + money(market.every_rise(ps)) + \".\")\n\ndef trades(ps):\n    while True:\n        s = trim(input(\"at most how many trades (1 to 5)> \"))\n        if s == \"\":\n            print(\"Cancelled.\")\n            return\n        if s == \"1\" or s == \"2\" or s == \"3\" or s == \"4\" or s == \"5\":\n            k = int(s)\n            r = market.best_k(ps, k)\n            if len(r[1]) == 0:\n                print(\"No trade makes money.\")\n                return\n            for t in r[1]:\n                print(\"  buy day \" + str(t[0] + 1) + \" at \" + money(ps[t[0]]) + \", sell day \" + str(t[1] + 1) + \" at \" + money(ps[t[1]]) + \": \" + money(ps[t[1]] - ps[t[0]]))\n            word = \"trades\"\n            if k == 1:\n                word = \"trade\"\n            print(\"At most \" + str(k) + \" \" + word + \", one share at a time: \" + money(r[0]) + \" in all.\")\n            return\n        print(\"Type a whole number from 1 to 5.\")\n\ndef new_prices(ps):\n    while True:\n        s = trim(input(\"prices, oldest first (2 to 40, like 12.40 13 11.85)> \"))\n        if s == \"\":\n            print(\"Cancelled.\")\n            return ps\n        out = prices_of(s)\n        if len(out) >= 2 and len(out) <= 40:\n            print(str(len(out)) + \" days of prices.\")\n            return out\n        print(\"Type 2 to 40 prices above 0, up to 99999.99, separated by spaces.\")\n\nprices = [1250, 1310, 1180, 1225, 1405, 1390, 1530, 1480, 1295, 1350, 1610, 1575, 1440, 1520, 1700, 1655]\nprint(\"== Stock chart ==\")\nprint(\"Daily prices: the best single trade, the best run of changes, and the best k trades.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) chart  2) best trade  3) best k trades  4) new prices  5) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        chart(prices)\n    elif choice == \"2\":\n        best(prices)\n    elif choice == \"3\":\n        trades(prices)\n    elif choice == \"4\":\n        prices = new_prices(prices)\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "market.eml",
      "eml": "# P085 stock chart - a run of daily prices in whole cents: the best single\n# buy and sell, the best run of daily changes, and the best profit from up\n# to k trades, each holding at most one share at a time.\n\ndef best_trade(prices):\n    # The corpus case stock-buy-sell-profit: one pass keeping the cheapest\n    # price so far. Returns [profit, buy day, sell day] (days from 0), or\n    # [0, -1, -1] when no trade makes money - not trading is allowed.\n    0 => best\n    -1 => buy\n    -1 => sell\n    0 => low\n    for d in [1:len(prices) - 1]:\n        if prices[d] - prices[low] > best:\n            prices[d] - prices[low] => best\n            low => buy\n            d => sell\n        if prices[d] < prices[low]:\n            d => low\n    return [best, buy, sell]\n\ndef best_run(xs):\n    # The corpus case max-subarray-kadane, keeping where the run starts:\n    # the largest sum of consecutive numbers (at least one), and its first\n    # and last index. With every number negative it is the least negative.\n    xs[0] => best\n    0 => bs\n    0 => be\n    xs[0] => cur\n    0 => cs\n    for i in [1:len(xs) - 1]:\n        if cur + xs[i] < xs[i]:\n            xs[i] => cur\n            i => cs\n        else:\n            cur + xs[i] => cur\n        if cur > best:\n            cur => best\n            cs => bs\n            i => be\n    return [best, bs, be]\n\ndef changes(prices):\n    [0] * (len(prices) - 1) => out\n    for d in [1:len(prices) - 1]:\n        prices[d] - prices[d - 1] => out[d - 1]\n    return out\n\ndef every_rise(prices):\n    # As many trades as you like: take every rise from one day to the next.\n    0 => s\n    for c in changes(prices):\n        if c > 0:\n            s + c => s\n    return s\n\ndef best_k(prices, k):\n    # At most k trades, by dynamic programming over the days. best[j][d] is\n    # the most that can be made by day d with at most j trades: either day\n    # d does nothing, or it sells a share bought on an earlier day b, with\n    # best[j - 1][b] made before buying. `hold` keeps the best of\n    # best[j - 1][b] - price[b] so far. Returns [profit, trades as [buy day,\n    # sell day]], the trades read back from the choices made.\n    len(prices) => n\n    # best[j][d]: the most made by day d with at most j trades closed\n    [0] * (k + 1) => best\n    for j in [0:k]:\n        [0] * n => best[j]\n    # came[j][d]: the buy day of the trade closing on day d, or -1 if day d\n    # closed none\n    [0] * (k + 1) => came\n    for j in [0:k]:\n        [-1] * n => came[j]\n    for j in [1:k]:\n        0 - prices[0] => hold\n        0 => hold_day\n        for d in [1:n - 1]:\n            best[j][d - 1] => keep\n            prices[d] + hold => sell\n            if sell > keep:\n                sell => best[j][d]\n                hold_day => came[j][d]\n            else:\n                keep => best[j][d]\n            if best[j - 1][d] - prices[d] > hold:\n                best[j - 1][d] - prices[d] => hold\n                d => hold_day\n    [] => trades\n    k => j\n    n - 1 => d\n    while j > 0 and d > 0:\n        if came[j][d] == -1:\n            d - 1 => d\n        else:\n            [[came[j][d], d]] + trades => trades\n            came[j][d] => d\n            j - 1 => j\n    return [best[k][n - 1], trades]\n",
      "python": "def best_trade(prices):\n    best = 0\n    buy = -1\n    sell = -1\n    low = 0\n    for d in range(1, len(prices)):\n        if prices[d] - prices[low] > best:\n            best = prices[d] - prices[low]\n            buy = low\n            sell = d\n        if prices[d] < prices[low]:\n            low = d\n    return [best, buy, sell]\n\ndef best_run(xs):\n    best = xs[0]\n    bs = 0\n    be = 0\n    cur = xs[0]\n    cs = 0\n    for i in range(1, len(xs)):\n        if cur + xs[i] < xs[i]:\n            cur = xs[i]\n            cs = i\n        else:\n            cur = cur + xs[i]\n        if cur > best:\n            best = cur\n            bs = cs\n            be = i\n    return [best, bs, be]\n\ndef changes(prices):\n    out = [0] * (len(prices) - 1)\n    for d in range(1, len(prices)):\n        out[d - 1] = prices[d] - prices[d - 1]\n    return out\n\ndef every_rise(prices):\n    s = 0\n    for c in changes(prices):\n        if c > 0:\n            s = s + c\n    return s\n\ndef best_k(prices, k):\n    n = len(prices)\n    best = [0] * (k + 1)\n    for j in range(0, k+1):\n        best[j] = [0] * n\n    came = [0] * (k + 1)\n    for j in range(0, k+1):\n        came[j] = [-1] * n\n    for j in range(1, k+1):\n        hold = 0 - prices[0]\n        hold_day = 0\n        for d in range(1, n):\n            keep = best[j][d - 1]\n            sell = prices[d] + hold\n            if sell > keep:\n                best[j][d] = sell\n                came[j][d] = hold_day\n            else:\n                best[j][d] = keep\n            if best[j - 1][d] - prices[d] > hold:\n                hold = best[j - 1][d] - prices[d]\n                hold_day = d\n    trades = []\n    j = k\n    d = n - 1\n    while j > 0 and d > 0:\n        if came[j][d] == -1:\n            d = d - 1\n        else:\n            trades = [[came[j][d], d]] + trades\n            d = came[j][d]\n            j = j - 1\n    return [best[k][n - 1], trades]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n3\n0\n6\nabc\n\n4\n12\n12 abc\n12 -3\n12 0\n12.345 13\n12. 13\n1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n\n5\n",
      "screen": "== Stock chart ==\nDaily prices: the best single trade, the best run of changes, and the best k trades.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 3\nat most how many trades (1 to 5)> 0\nType a whole number from 1 to 5.\nat most how many trades (1 to 5)> 6\nType a whole number from 1 to 5.\nat most how many trades (1 to 5)> abc\nType a whole number from 1 to 5.\nat most how many trades (1 to 5)> \nCancelled.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 4\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 12\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 12 abc\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 12 -3\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 12 0\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 12.345 13\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 12. 13\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nType 2 to 40 prices above 0, up to 99999.99, separated by spaces.\nprices, oldest first (2 to 40, like 12.40 13 11.85)> \nCancelled.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n2\n3\n1\n3\n2\n3\n5\n4\n10 9 8.5 7\n2\n3\n2\n4\n5 5 5\n2\n1\n5\n",
      "screen": "== Stock chart ==\nDaily prices: the best single trade, the best run of changes, and the best k trades.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 1\n  day  1  12.50  ######\n  day  2  13.10  ##########\n  day  3  11.80  #\n  day  4  12.25  ####\n  day  5  14.05  #################\n  day  6  13.90  ################\n  day  7  15.30  ###########################\n  day  8  14.80  #######################\n  day  9  12.95  #########\n  day 10  13.50  #############\n  day 11  16.10  #################################\n  day 12  15.75  ##############################\n  day 13  14.40  ####################\n  day 14  15.20  ##########################\n  day 15  17.00  ########################################\n  day 16  16.55  ####################################\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 2\nBest single trade: buy on day 3 at 11.80, sell on day 15 at 17.00 - 5.20 a share.\nThe best run of daily changes is days 3 to 15, adding up to 5.20.\nThe same thing: a trade's profit is the sum of the daily changes it holds through.\nTrading every rise, as often as you like: 10.00.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 3\nat most how many trades (1 to 5)> 1\n  buy day 3 at 11.80, sell day 15 at 17.00: 5.20\nAt most 1 trade, one share at a time: 5.20 in all.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 3\nat most how many trades (1 to 5)> 2\n  buy day 3 at 11.80, sell day 7 at 15.30: 3.50\n  buy day 9 at 12.95, sell day 15 at 17.00: 4.05\nAt most 2 trades, one share at a time: 7.55 in all.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 3\nat most how many trades (1 to 5)> 5\n  buy day 1 at 12.50, sell day 2 at 13.10: 0.60\n  buy day 3 at 11.80, sell day 5 at 14.05: 2.25\n  buy day 6 at 13.90, sell day 7 at 15.30: 1.40\n  buy day 9 at 12.95, sell day 11 at 16.10: 3.15\n  buy day 13 at 14.40, sell day 15 at 17.00: 2.60\nAt most 5 trades, one share at a time: 10.00 in all.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 4\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 10 9 8.5 7\n4 days of prices.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 2\nNo single trade makes money: the price only falls (or stays). Not trading is the best.\nThe best run of daily changes is days 2 to 3, adding up to -0.50.\nEvery daily change is a fall, so the best run is the smallest fall - while the best trade is not to trade.\nTrading every rise, as often as you like: 0.00.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 3\nat most how many trades (1 to 5)> 2\nNo trade makes money.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 4\nprices, oldest first (2 to 40, like 12.40 13 11.85)> 5 5 5\n3 days of prices.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 2\nNo single trade makes money: the price only falls (or stays). Not trading is the best.\nThe best run of daily changes is days 1 to 2, adding up to 0.00.\nNo day rises, so the best run adds up to nothing - and the best trade is not to trade.\nTrading every rise, as often as you like: 0.00.\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 1\n  day  1  5.00  #\n  day  2  5.00  #\n  day  3  5.00  #\n\n1) chart  2) best trade  3) best k trades  4) new prices  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "stock-buy-sell-profit",
      "caseId": "105-stock-buy-sell-profit",
      "title": "Best single buy/sell profit"
    },
    {
      "slug": "max-subarray-kadane",
      "caseId": "091-max-subarray-kadane",
      "title": "Maximum subarray (Kadane's algorithm)"
    }
  ],
  "updated": "2026-10-15"
}
