回精華區
作者Efen.bbs@bbs.med.ncku.edu.tw (我~是~胖~子) 看板: plan
標題股市程式碼
時間迴 風 谷 (2004/07/16 Fri 22:21:40) Updated: 2004/08/16
說明:

1.不休市
    本股市為24小時不收市,沒有期限,期望值近於零,也就是並非放著就會
    保證必定賺錢,而是需要動態的操作。

2.漲跌計算
    依照成交量的多寡,而有不同的漲跌機率,當然,愈高就愈有機會上漲,
    愈低就愈有機會下跌。
    一次的漲跌幅度目前維持在-2%~+5%點之間,會受各股本身的成交量的影響。

3.配額量
    每次價格變動後,各股有不同的配額增加(0~5)

4.開盤價
    取當天零點過後,第一次變動後的價格為開盤價(目前為0:05)

5.股價變動
    目前為每小時變換三次,分別為5、25、45分,各一次

6.成交量
    依照實際股市,以買入+賣出的股份為總成交量,每天重新計算一次

7.證交稅
    每次賣出時,抽稅百分之十,避免故意拉高成交量及短線交易

8.附有每次變動的股價紀錄、走勢圖(小時為單位)、個人可查詢自己的持股情況

9.每天會產生走勢圖(有總成交量)、股價紀錄

-------------------------------------------------------------------------

: include/global.h

#define BMTA_LOGFILE    "run/bmta.log"  /* 收外部信的記錄 */

+ #define FN_RUN_STOCK          "run/stock"         /* 股市資料檔 */
+ #define FN_RUN_STOCK_RECORD   "run/stock.record"  /* 漲跌紀錄 */
+ #define FN_RUN_STOCK_INFO     "run/stock.info"    /* 股市走勢 */

: include/struct.h 加入以下這段

#ifdef HAVE_GAME

#define MAXSTOCK      8             /* 八家 */

typedef struct
{
  int price[MAXSTOCK];          /* 價格 */
  int start[MAXSTOCK];          /* 每日初始價 */
  int change[MAXSTOCK];         /* 漲跌 */
  int stillnum[MAXSTOCK];       /* 剩餘數量 */
  int ordernum[MAXSTOCK];       /* 成交量 */
}      STOCK;

#endif

-------------------------------------------------------------------------

: game/stock.c 新增此程式

/*-------------------------------------------------------*/
/* stock.c      ( NTHU CS MapleBBS Ver 3.10 )            */
/*-------------------------------------------------------*/
/* target : 股市交易                                     */
/* create : 04/07/16                                     */
/* update : 04/07/27                                     */
/* author : Efen.bbs@bbs.med.ncku.edu.tw                 */
/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw                 */
/*-------------------------------------------------------*/


#include "bbs.h"

#ifdef HAVE_GAME

#define FN_STOCK      "stock"       /* 個人的股市檔案-各股擁有張數 */

static char stockname[MAXSTOCK][9] =
{
  "上 閤 屋", "新 天 地", "遠東百貨", "統聯客運",
  "國賓影城", "生活工坊", "寶 雅 館", "成大醫學"
};

static int own[MAXSTOCK];


/*-------------------------------------------------------*/
/* 螢幕控制                                              */
/*-------------------------------------------------------*/


static void
show_stock_data(sto)
  STOCK *sto;
{
  int i, change, total, allchange, allordernum, allmoney;

  move(2, 0);
  outs("   \033[1;42m   編號  \033[36m商店名稱    \033[33m價  格"
    "\033[37m(\033[31m漲    \033[32m跌\033[37m)  目前數量 今日成交量"
    "   擁有數量   \033[m\n");
  outs("   \033[46m◇──────────────────────"
    "────────────◇\033[m\n");

  total = change = ordernum = allmoney = 0;

  for (i = 0; i < MAXSTOCK; i++)
  {
    change = sto->change[i];

    total += sto->price[i];
    allchange += change;
    allordernum += sto->ordernum[i];
    allmoney += own[i] * sto->price[i];

    prints("\033[1m%8d.\033[36m%11s \033[3%dm%8d(%s %8d)"
      "\033[37m%10d%11d%11d\033[m\n",
      i + 1, stockname[i],
      change ? (change > 0 ? 1 : 2) : 7,
      sto->price[i],
      change ? (change > 0 ? "△" : "▽") : "=",
      abs(change),
      sto->stillnum[i], sto->ordernum[i], own[i]);
  }

  outs("   \033[46m◇──────────────────────"
    "────────────◇\033[m\n");

  prints("\033[1;37m       加權股價總指數:\033[3%dm%d  %2s %d"
    "\033[37m      總成交量:%d\033[m\n\n",
    allchange ? (allchange > 0 ? 1 : 2) : 7, total,
    allchange ? (allchange > 0 ? "▲" : "▼") : "=", allchange, allordernum);

  prints("   \033[1;32;45m您的股價總值:%d 銀幣\033[m\n\n", allmoney);
  prints("   \033[1;33;45m您的資本金額:%d 銀幣\033[m", cuser.money);
}


/*-------------------------------------------------------*/
/* 股市指令                                              */
/*-------------------------------------------------------*/


static void
stock_query(sto)
  STOCK *sto;
{
  int i;

  clear();
  outs("\033[1;33m櫃台小姐給您一張清單:\033[\n");
  outs("\033[1;32m股市:\033[32m持股一覽表\033[m\n\n");
  for (i = 0; i < MAXSTOCK; i++)
  {
    prints("\033[1;3%dm %d.您擁有 %s 的股份共 %8d 張,股價 [%d]\033[m\n",
      i & 7, i, stockname[i], own[i], sto->price[i]);
  }
  vmsg(NULL);
}


static void
stock_sell(sto)
  STOCK *sto;
{
  int i, num, money;
  char buf[80], ans[8];

  sprintf(buf, "要賣哪家(1-%d)?", MAXSTOCK);
  vget(b_lines, 0, buf, ans, 2, DOECHO);
  i = atoi(ans) - 1;
  if (i < 0 || i >= MAXSTOCK)
    return;

  if (!own[i])
  {
    vmsg("已無股份可賣");
    return;
  }

  sprintf(buf, "要賣幾張(1-%d)?", own[i]);
  vget(b_lines, 0, buf, ans, 5, DOECHO);
  num = atoi(ans);
  if (num <= 0 || num > own[i])
    return;

  /* 重新取得目前股市並更新 */
  rec_get(FN_RUN_STOCK, sto, sizeof(STOCK), 0);
  sto->stillnum[i] += num;
  sto->ordernum[i] += num;
  rec_put(FN_RUN_STOCK, sto, sizeof(STOCK), 0, NULL);

  /* 更新持股 */
  own[i] -= num;
  usr_fpath(buf, cuser.userid, FN_STOCK);
  rec_put(buf, own, sizeof(own), 0, NULL);

  money = sto->price[i] * num * 9 / 10;    /* 手續費 */
  addmoney(money);

  sprintf(buf, "賣出 %s %d 張,收入 %d 銀幣!", stockname[i], num, money);
  vmsg(buf);
}


static void
stock_buy(sto)
  STOCK *sto;
{
  int i, num, money;
  char buf[80], ans[8];

  sprintf(buf, "要買哪家(1-%d)?", MAXSTOCK);
  vget(b_lines, 0, buf, ans, 2, DOECHO);
  i = atoi(ans) - 1;
  if (i < 0 || i >= MAXSTOCK)
    return;

  if (sto->stillnum[i] <= 0)
  {
    vmsg("已無股份可買");
    return;
  }

  money = cuser.money / sto->price[i];
  sprintf(buf, "要買幾張(1-%d)?", money);
  vget(b_lines, 0, buf, ans, 5, DOECHO);
  num = atoi(ans);
  if (num <= 0 || num > money)
    return;

  /* 重新取得目前股市 */
  rec_get(FN_RUN_STOCK, sto, sizeof(STOCK), 0);

  if (sto->stillnum[i] < num)
  {
    vmsg("股份剛被搶走了,下次請早!");
    return;
  }

  money = sto->price[i] * num;
  if (cuser.money < money)
  {
    vmsg("股價已變動,您不夠金錢購買");
    return;
  }

  /* 更新股市 */
  sto->stillnum[i] -= num;
  sto->ordernum[i] += num;
  rec_put(FN_RUN_STOCK, sto, sizeof(STOCK), 0, NULL);

  /* 更新持股 */
  own[i] += num;
  usr_fpath(buf, cuser.userid, FN_STOCK);
  rec_put(buf, own, sizeof(own), 0, NULL);

  cuser.money -= money;

  sprintf(buf, "買進 %s %d 張,花費 %d 銀幣!", stockname[i], num, money);
  vmsg(buf);
}


/*-------------------------------------------------------*/
/* 主程式                                                */
/*-------------------------------------------------------*/


int
main_stock()
{
  int i;
  char fpath[64];
  STOCK sto;

  if (cutmp->status & STATUS_COINLOCK)
  {
    vmsg(MSG_COINLOCK);
    return XEASY;
  }

  /* 我的持股 */
  usr_fpath(fpath, cuser.userid, FN_STOCK);
  if (rec_get(fpath, own, sizeof(own), 0))
  {
    memset(own, 0, sizeof(own));
    rec_add(fpath, own, sizeof(STOCK));
  }

  /* 目前股市 */
  if (rec_get(FN_RUN_STOCK, &sto, sizeof(STOCK), 0))
  {
    for (i = 0; i < MAXSTOCK; i++)
    {
      sto.price[i] = 100;
      sto.start[i] = 100;
      sto.change[i] = 0;
      sto.stillnum[i] = 100000;
      sto.ordernum[i] = 0;

    }
    rec_add(FN_RUN_STOCK, &sto, sizeof(STOCK));
  }

  while (1)
  {
    clear();
    outs("\033[1;36;44m ★ ★ ★ ★  \033[31m【 \033[35m證券交易所\033[31m 】"
      "  \033[36m★ ★ ★ ★         [\033[32mDesign by Efen\033[36m] \033[m");

    show_stock_data(&sto);

    switch (vans("[B:買 S:賣 C:查詢 F:漲跌紀錄 I:走勢圖 Q:離開]"))
    {
    case 'c':
      stock_query(&sto);
      break;

    case 'f':
      more(FN_RUN_STOCK_RECORD, NULL);
      break;

    case 'i':
      more(FN_RUN_STOCK_INFO, NULL);
      break;

    case 's':
      stock_sell(&sto);
      break;

    case 'b':
      stock_buy(&sto);
      break;


    case 'q':
      return 0;
    }
  }
}
#endif    /* HAVE_GAME */

---------------------------------------------------------------------------

: util/stock-change.c 新增此程式

/*-------------------------------------------------------*/
/* stock-change.c ( NTHU CS MapleBBS Ver 3.10 )          */
/*-------------------------------------------------------*/
/* target : 股市交易變化                                 */
/* create : 04/07/16                                     */
/* update : 04/07/27                                     */
/* author : Efen.bbs@bbs.med.ncku.edu.tw                 */
/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw                 */
/*-------------------------------------------------------*/


#include "bbs.h"

#ifdef HAVE_GAME

#define MAX_LINE      16

static char *fn_tmpfile = "run/stock.change";
static int ordernum = 0;


static char stockname[MAXSTOCK][9] =
{
  "上 閤 屋", "新 天 地", "遠東百貨", "統聯客運",
  "國賓影城", "生活工坊", "寶 雅 館", "成大醫學"
};


static void
ansi_puts(fp, buf, mode)
  FILE *fp;
  char *buf, mode;
{
  static char state = '0';

  if (state != mode)
    fprintf(fp, "\033[3%cm", state = mode);
  if (*buf)
  {
    fprintf(fp, buf);
    *buf = '\0';
  }
}


static void
draw_usies(ptime)
  struct tm *ptime;
{
  int num, hour, max, min, item, i, j, over;
  char buf[ANSILINELEN];
  FILE *fp;
  int act[24];

  for (i = 0; i < 24; i++)
    act[i] = 0;

  i = 0;

  if (fp = fopen(fn_tmpfile, "r"))
  {
    while ((fscanf(fp, "%d", &num)) != EOF)
    {
      act[i] = num;
      i++;
    }
    fclose(fp);
  }
  else
    return;

  max = act[0];
  min = act[0];

  for (i = 0; i < 24; i++)
  {
    if (act[i] > max)
      max = act[i];
    else if (act[i] < min && act[i] != 0)
      min = act[i];
  }

  min = (min / 100) * 100;

  for (i = 0; i < 24; i++)
  {
    if (act[i] != 0)
      act[i] -= min;
  }

  max -= min;

  item = max / MAX_LINE + 1;
  over = max > 1000;

  fp = fopen(FN_RUN_STOCK_INFO, "w");

  fprintf(fp, "\t\t\t\033[1;33;46m [%02d/%02d/%02d] 今日股市走勢 \033[40m\n",
    ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday);

  for (i = MAX_LINE + 1; i > 0; i--)
  {
    strcpy(buf, "   ");
    for (j = 0; j < 24; j++)
    {
      max = item * i;
      hour = act[j];
      if (hour && (max > hour) && (max - item <= hour))
      {
        ansi_puts(fp, buf, '3');
        if (over)
          hour = (hour + 5) / 10;
        fprintf(fp, "%-3d", hour);
      }
      else if (max <= hour)
      {
        ansi_puts(fp, buf, '1');
        fprintf(fp, "█ ");
      }
      else
        strcat(buf, "   ");
    }
    fprintf(fp, "\n");
  }

  fprintf(fp, "\033[34m"
    "  ╒════════════════════"
    "═══════════════╕\n  \033[32m"
    "0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 "
    "15 16 17 18 19 20 21 22 23\n"
    "\t%s\t\033[m\n"
    "\033[35m基值:\033[37m%-10d\033[35m總成交量:\033[1;37m%d\033[m\n",
    over ? "\033[35m單位:\033[37m10\033[m" : "", min, ordernum);
  fclose(fp);

  if (ptime->tm_hour == 23)
    unlink(fn_tmpfile);
}


static int
price_change(sto, i, ordernum)    /* 決定股價漲跌 */
  STOCK *sto;
  int i;
  int ordernum;
{
  int rate;

  /* 此股成交量佔總成交量的比例越高,上漲的機率越高 */
  rate = sto->ordernum[i] * 4;
  if (rate > ordernum * 3)          /* 本股成交量佔大盤 75%~100% */
    rate = 101;                     /* 期望上漲股價 3% */
  else if (rate > ordernum * 2)     /* 本股成交量佔大盤 50%~74% */
    rate = 100;                     /* 期望上漲股價 2% */
  else if (rate > ordernum * 1)     /* 本股成交量佔大盤 25%~49% */
    rate = 99;                      /* 期望上漲股價 1% */
  else                              /* 本股成交量佔大盤  0%~24% */
    rate = 98;                      /* 期望上漲股價 0% */

  rate = sto->price[i] * (rnd(5) + rate) / 100;
  if (rate <= 0)
    rate = 1;

  sto->change[i] = rate - sto->price[i];
  sto->price[i] = rate;
}


int
main()
{
  int i, totalprice;
  STOCK sto;
  time_t now;
  struct tm *ptime;
  FILE *fp;

  now = time(NULL);
  ptime = localtime(&now);

  chdir(BBSHOME);

  /* 取得目前股市 */
  rec_get(FN_RUN_STOCK, &sto, sizeof(STOCK), 0);

  /* 算總成交量 */
  for (i = 0; i < MAXSTOCK; i++)
    ordernum += sto.ordernum[i];

  /* 更新股市 */
  totalprice = 0;
  srand(now);
  for (i = 0; i < MAXSTOCK; i++)
  {
    price_change(&sto, i, ordernum);
    sto.stillnum[i] += rnd(6);

    if (ptime->tm_hour == 0 && ptime->tm_min == 5)
    {
      sto.start[i] = sto.price[i];
      sto.ordernum[i] = 0;
    }

    totalprice += sto.price[i];
  }
  rec_put(FN_RUN_STOCK, &sto, sizeof(STOCK), 0, NULL);

  /* 寫入漲跌紀錄 */
  if (fp = fopen(FN_RUN_STOCK_RECORD, "a"))
  {
    fprintf(fp, "\033[1;33m%s\033[m\n", Btime(&now));

    for (i = 0; i < MAXSTOCK; i++)
      fprintf(fp, "%9s", stockname[i]);
    fprintf(fp, "\n");

    for (i = 0; i < MAXSTOCK; i++)
      fprintf(fp, "%8d ", sto.price[i]);
    fprintf(fp, "\n\n");

    fclose(fp);
  }

  /* 畫走勢圖 */
  if (ptime->tm_min == 5)
  {
    fp = fopen(fn_tmpfile, "a+");
    fprintf(fp, "%d\n", totalprice / 1000);
    fclose(fp);
    draw_usies(ptime);
  }

  return 0;
}
#else
int
main()
{
  printf("You should define HAVE_GAME first.\n");
  return -1;
}
#endif    /* HAVE_GAME */


---------------------------------------------------------------------------

: util/account.c

    sprintf(title, "%s酸甜苦辣留言板", date);
    keeplog(FN_RUN_NOTE_ALL, NULL, title, 2);

+#ifdef HAVE_GAME
+   sprintf(title, "%s股市漲跌紀錄", date);
+   keeplog(FN_RUN_STOCK_RECORD, NULL, title, 2);

+   sprintf(title, "%s股市走勢", date);
+   keeplog(FN_RUN_STOCK_INFO, NULL, title, 0);
+#endif

-------------------------------------------------------------------------

: crontab -e 在最後加入

# 股市變換
5,25,45 * * * * bin/stock-change > /dev/null 2>&1



.....差不多要放下主機管理的工作了....就把這陣子努力的成果跟大家分享囉....
這算是本站最大的一個修修改改想想半自創的程式了吧
--
 『╭╯成大醫學╭╯ ﹌  ☆ ii bbs.med.ncku.edu.tw ii ☆  ﹋     
 ╭╯迴 風 谷╭╯』 →From:140.116.144.137                            
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻