电力改革如火如荼,针对电力交易的广东规则,本文进行了详细地阐述并附上了代码与实例,供大家一起交流学习。
本竞价规则参考广东电力交易中心目前的竞价规则。
该内容及算例引用了售电市场研修院
的内容,并感谢北京清软创新科技股份有限公司
研究中心主任罗欣
的讲解。
交易牵涉两大角色,卖电方和买电方:
交易牵涉一个变量:
也就是说,买卖双方的电量不会全部成交。
例如,如果发电企业意向申报交易规模100万千瓦时,售电公司意向申报规模80万千瓦时,电力大用户意向申报20万千瓦时。
若设置成交比例为80%,则竞争交易电力规模为100*0.8=80万千瓦时。
报价规则牵涉的变量有:
所报价差必须在指定的价差范围内。
例如:
发电企业申报价差范围:-50到-500厘/千瓦时。
售电公司及电力用户申报价差范围:0到-100厘/千瓦时。
发电企业上网电价为:500厘/千瓦时,申报价差:-100厘/千瓦时,表示期望卖出电价为400厘/千瓦时。
售电公司及电力用户目录电价为500厘/千瓦时,申报价差为-50千瓦时,表示期望买入电价为450厘/千瓦时。
这里,首先介绍下价差对的概念:
例如:发电企业申报价差为-100厘/千瓦时,电力大用户申报价差为-50厘/千瓦时,价差对为-100-(-50)= -50厘/千瓦时。
需要注意的是:
结算规则主要涉及两点:
下面附上一个例子,并附上相应代码仅供交流学习。
该交易涉及的发电企业与用电大用户数据如下:
每轮的交易情况概述如下:
发电企业的交易结算如下:
电力用户的交易结算如下:
# coding: utf-8
# In[1]:
from __future__ import division
import pandas as pd
# # 基础类定义
# In[2]:
# 定义类
class Producer:
def __init__(self,name,amount,price):
self.name = name
self.amount = amount
self.price = price
self.amount_left = amount
self.accu_money = 0
self.accu_money_diff = 0
def __repr__(self):
return "" % (self.name, self.amount, self.price, self.amount_left)
class User:
def __init__(self,name,amount,price):
self.name = name
self.amount = amount
self.price = price
self.amount_left = amount
self.accu_money = 0
self.accu_money_diff = 0
def __repr__(self):
return "" % (self.name, self.amount, self.price, self.amount_left)
class Process:
def __init__(self,amount,p_price,u_price):
self.amount = amount
self.p_price = p_price
self.u_price = u_price
self.diff_price = p_price-u_price
def __repr__(self):
return "" % (self.amount, self.p_price, self.u_price, self.diff_price)
# # 参数设置
# In[3]:
# 设置买卖双方的参数
producers_name = ['A','B','C','D','E']
producers_amount = [14975,18099,59015,53707,87809]
producers_price = [-500,-334.3,-145.7,-105.8,-60.6]
users_name = ['1','2','3','4','5']
users_amount = [67983,39403,64478,38592,19799]
users_price = [-45,-35.8,-26.7,-14.3,-0.1]
# In[4]:
producers = []
for name,amount,price in zip(producers_name,producers_amount,producers_price):
producers.append(Producer(name,amount,price))
users = []
for name,amount,price in zip(users_name,users_amount,users_price):
users.append(User(name,amount,price))
# sort producers and users
import operator
producers_inline = sorted(producers, key=operator.attrgetter('price'), reverse=False)
users_inline = sorted(users, key=operator.attrgetter('price'), reverse=True)
# In[5]:
producers_inline
# In[6]:
users_inline
# # 交易撮合
# In[7]:
# 确定针对producers_inline和users_inline的指针
producer_pt = 0
user_pt = 0
# 指定参数
deal_ratio_proc = 0.8 #发电企业的成交比例
deal_amounts = 0 #成交数量累计
deal_amounts_max = sum(producers_amount)*deal_ratio_proc #最大的成交数量
df = pd.DataFrame(columns=('发电企业', '申报电量', '申报价差','售电公司', '申报电量', '申报价差', '价差', '成交电量')) #数据框初始化
df_i = 0 #数据框的行指针
processes = [] #累计每个交易流程
flag_stop = False #判断是否到达成交比例的flag
# 交易流程
while user_pt < len(users_inline) and producer_pt < len(producers_inline):
cur_producer = producers_inline[producer_pt]
cur_user = users_inline[user_pt]
diff_amount = cur_producer.amount_left - cur_user.amount_left
diff_price = float(cur_producer.price) - float(cur_user.price)
# 只有当价差对为负的时候才有可能成交
if diff_price > 0:
break
deal_amount = min(cur_producer.amount_left,cur_user.amount_left)
deal_amounts += deal_amount
# 只有当交易量在规定范围内才有可能成交,否则将flag_stop设置为True
if deal_amounts > deal_amounts_max:
curr_del_amount = deal_amounts_max - (deal_amounts-deal_amount)
flag_stop = True
else:
curr_del_amount = deal_amount
# 针对每次交易过程的数据统计计算
##输出信息
print "P:%s U:%s P_left_Amount:%6s U_left_Amount:%6s Deal_Amount:%6s Price_Differ:%s" % (cur_producer.name, cur_user.name, cur_producer.amount_left, cur_user.amount_left, int(curr_del_amount), cur_producer.price-cur_user.price)
##进程信息统计
processes.append(Process(int(curr_del_amount),cur_producer.price,cur_user.price))
##累计电费与累计价差电费
cur_user.accu_money += cur_user.price*int(curr_del_amount)
cur_user.accu_money_diff += (cur_producer.price-cur_user.price)*int(curr_del_amount)
cur_producer.accu_money += cur_producer.price*int(curr_del_amount)
cur_producer.accu_money_diff += (cur_producer.price-cur_user.price)*int(curr_del_amount)
##数据库信息统计
df.loc[df_i] = [cur_producer.name,cur_producer.amount,cur_producer.price, cur_user.name,cur_user.amount,cur_user.price, cur_producer.price-cur_user.price,curr_del_amount]
df_i += 1
##判断终止条件
if flag_stop:
cur_user.amount_left -= curr_del_amount
cur_producer.amount_left -= curr_del_amount
break
##判断交易方向,卖者还是买者退出市场
if diff_amount == 0:
user_pt += 1
producer_pt += 1
cur_user.amount_left = 0
cur_producer.amount_left = 0
elif diff_amount < 0: #卖的少,买的多,卖者退出市场
producer_pt += 1
cur_user.amount_left -= curr_del_amount
cur_producer.amount_left = 0
else: #卖的多,买的少,买者退出市场
user_pt += 1
cur_user.amount_left = 0
cur_producer.amount_left -= curr_del_amount
# # 交易整理
# In[8]:
df
# # 结算情况
# ## 发电公司
# In[9]:
producers_accounts = pd.DataFrame([(i.name,i.amount,i.amount_left,i.accu_money,i.accu_money_diff)for i in producers],columns=('name','amount','amount_left','accu_money','accu_money_diff'))
# In[10]:
producers_accounts['price'] = producers_price
producers_accounts['amount_deal'] = producers_accounts['amount'] - producers_accounts['amount_left']
producers_accounts['accu_money_ratio'] = producers_accounts['accu_money']/sum(producers_accounts['accu_money'])
producers_accounts['return_money'] = producers_accounts['accu_money_ratio']*sum(producers_accounts['accu_money_diff'])*0.5
producers_accounts['real_monty'] = producers_accounts['accu_money'] - producers_accounts['return_money']
producers_accounts['real_price'] = producers_accounts['real_monty']/producers_accounts['amount_deal']
# In[11]:
columns_ordered = ['name', 'price','amount', 'amount_left','amount_deal', 'accu_money','accu_money_ratio', 'accu_money_diff', 'return_money','real_monty', 'real_price']
producers_accounts = producers_accounts[columns_ordered]
producers_accounts.columns = ['名称','申报价差','申报电量','剩余电量','中标电量','累计电费(不含返还)','累计电费占比','累计价差电费', '返还电费','中标电费(含返还)','中标价差']
producers_accounts
# ## 售电公司与电力用户
# In[12]:
users_accounts = pd.DataFrame([(i.name,i.amount,i.amount_left,i.accu_money,i.accu_money_diff)for i in users],columns=('name','amount','amount_left','accu_money','accu_money_diff'))
# In[13]:
users_accounts['price'] = users_price
users_accounts['amount_deal'] = users_accounts['amount'] - users_accounts['amount_left']
users_accounts['accu_money_ratio'] = users_accounts['accu_money']/sum(users_accounts['accu_money'])
users_accounts['return_money'] = users_accounts['accu_money_ratio']*sum(users_accounts['accu_money_diff'])*0.5
users_accounts['real_monty'] = users_accounts['accu_money'] + users_accounts['return_money']
users_accounts['real_price'] = users_accounts['real_monty']/users_accounts['amount_deal']
# In[14]:
columns_ordered = ['name', 'price','amount', 'amount_left','amount_deal', 'accu_money','accu_money_ratio', 'accu_money_diff', 'return_money','real_monty', 'real_price']
users_accounts = users_accounts[columns_ordered]
users_accounts.columns = ['名称','申报价差','申报电量','剩余电量','中标电量','累计电费(不含返还)','累计电费占比','累计价差电费', '返还电费','中标电费(含返还)','中标价差']
users_accounts